18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#define _GNU_SOURCE
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <errno.h>
68c2ecf20Sopenharmony_ci#include <fcntl.h>
78c2ecf20Sopenharmony_ci#include <linux/limits.h>
88c2ecf20Sopenharmony_ci#include <signal.h>
98c2ecf20Sopenharmony_ci#include <stdio.h>
108c2ecf20Sopenharmony_ci#include <stdlib.h>
118c2ecf20Sopenharmony_ci#include <string.h>
128c2ecf20Sopenharmony_ci#include <sys/stat.h>
138c2ecf20Sopenharmony_ci#include <sys/types.h>
148c2ecf20Sopenharmony_ci#include <sys/wait.h>
158c2ecf20Sopenharmony_ci#include <unistd.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "cgroup_util.h"
188c2ecf20Sopenharmony_ci#include "../clone3/clone3_selftests.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic ssize_t read_text(const char *path, char *buf, size_t max_len)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	ssize_t len;
238c2ecf20Sopenharmony_ci	int fd;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	fd = open(path, O_RDONLY);
268c2ecf20Sopenharmony_ci	if (fd < 0)
278c2ecf20Sopenharmony_ci		return fd;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	len = read(fd, buf, max_len - 1);
308c2ecf20Sopenharmony_ci	if (len < 0)
318c2ecf20Sopenharmony_ci		goto out;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	buf[len] = 0;
348c2ecf20Sopenharmony_ciout:
358c2ecf20Sopenharmony_ci	close(fd);
368c2ecf20Sopenharmony_ci	return len;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic ssize_t write_text(const char *path, char *buf, ssize_t len)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	int fd;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	fd = open(path, O_WRONLY | O_APPEND);
448c2ecf20Sopenharmony_ci	if (fd < 0)
458c2ecf20Sopenharmony_ci		return fd;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	len = write(fd, buf, len);
488c2ecf20Sopenharmony_ci	if (len < 0) {
498c2ecf20Sopenharmony_ci		close(fd);
508c2ecf20Sopenharmony_ci		return len;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	close(fd);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return len;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cichar *cg_name(const char *root, const char *name)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	size_t len = strlen(root) + strlen(name) + 2;
618c2ecf20Sopenharmony_ci	char *ret = malloc(len);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	snprintf(ret, len, "%s/%s", root, name);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return ret;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cichar *cg_name_indexed(const char *root, const char *name, int index)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	size_t len = strlen(root) + strlen(name) + 10;
718c2ecf20Sopenharmony_ci	char *ret = malloc(len);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	snprintf(ret, len, "%s/%s_%d", root, name, index);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	return ret;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cichar *cg_control(const char *cgroup, const char *control)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	size_t len = strlen(cgroup) + strlen(control) + 2;
818c2ecf20Sopenharmony_ci	char *ret = malloc(len);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	snprintf(ret, len, "%s/%s", cgroup, control);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return ret;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ciint cg_read(const char *cgroup, const char *control, char *buf, size_t len)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	char path[PATH_MAX];
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	snprintf(path, sizeof(path), "%s/%s", cgroup, control);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (read_text(path, buf, len) >= 0)
958c2ecf20Sopenharmony_ci		return 0;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return -1;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ciint cg_read_strcmp(const char *cgroup, const char *control,
1018c2ecf20Sopenharmony_ci		   const char *expected)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	size_t size;
1048c2ecf20Sopenharmony_ci	char *buf;
1058c2ecf20Sopenharmony_ci	int ret;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* Handle the case of comparing against empty string */
1088c2ecf20Sopenharmony_ci	if (!expected)
1098c2ecf20Sopenharmony_ci		return -1;
1108c2ecf20Sopenharmony_ci	else
1118c2ecf20Sopenharmony_ci		size = strlen(expected) + 1;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	buf = malloc(size);
1148c2ecf20Sopenharmony_ci	if (!buf)
1158c2ecf20Sopenharmony_ci		return -1;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (cg_read(cgroup, control, buf, size)) {
1188c2ecf20Sopenharmony_ci		free(buf);
1198c2ecf20Sopenharmony_ci		return -1;
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	ret = strcmp(expected, buf);
1238c2ecf20Sopenharmony_ci	free(buf);
1248c2ecf20Sopenharmony_ci	return ret;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ciint cg_read_strstr(const char *cgroup, const char *control, const char *needle)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	char buf[PAGE_SIZE];
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (cg_read(cgroup, control, buf, sizeof(buf)))
1328c2ecf20Sopenharmony_ci		return -1;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return strstr(buf, needle) ? 0 : -1;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cilong cg_read_long(const char *cgroup, const char *control)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	char buf[128];
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (cg_read(cgroup, control, buf, sizeof(buf)))
1428c2ecf20Sopenharmony_ci		return -1;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	return atol(buf);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cilong cg_read_key_long(const char *cgroup, const char *control, const char *key)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	char buf[PAGE_SIZE];
1508c2ecf20Sopenharmony_ci	char *ptr;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (cg_read(cgroup, control, buf, sizeof(buf)))
1538c2ecf20Sopenharmony_ci		return -1;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	ptr = strstr(buf, key);
1568c2ecf20Sopenharmony_ci	if (!ptr)
1578c2ecf20Sopenharmony_ci		return -1;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	return atol(ptr + strlen(key));
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cilong cg_read_lc(const char *cgroup, const char *control)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	char buf[PAGE_SIZE];
1658c2ecf20Sopenharmony_ci	const char delim[] = "\n";
1668c2ecf20Sopenharmony_ci	char *line;
1678c2ecf20Sopenharmony_ci	long cnt = 0;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (cg_read(cgroup, control, buf, sizeof(buf)))
1708c2ecf20Sopenharmony_ci		return -1;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	for (line = strtok(buf, delim); line; line = strtok(NULL, delim))
1738c2ecf20Sopenharmony_ci		cnt++;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return cnt;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ciint cg_write(const char *cgroup, const char *control, char *buf)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	char path[PATH_MAX];
1818c2ecf20Sopenharmony_ci	ssize_t len = strlen(buf);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	snprintf(path, sizeof(path), "%s/%s", cgroup, control);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (write_text(path, buf, len) == len)
1868c2ecf20Sopenharmony_ci		return 0;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return -1;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ciint cg_find_unified_root(char *root, size_t len)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	char buf[10 * PAGE_SIZE];
1948c2ecf20Sopenharmony_ci	char *fs, *mount, *type;
1958c2ecf20Sopenharmony_ci	const char delim[] = "\n\t ";
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (read_text("/proc/self/mounts", buf, sizeof(buf)) <= 0)
1988c2ecf20Sopenharmony_ci		return -1;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	/*
2018c2ecf20Sopenharmony_ci	 * Example:
2028c2ecf20Sopenharmony_ci	 * cgroup /sys/fs/cgroup cgroup2 rw,seclabel,noexec,relatime 0 0
2038c2ecf20Sopenharmony_ci	 */
2048c2ecf20Sopenharmony_ci	for (fs = strtok(buf, delim); fs; fs = strtok(NULL, delim)) {
2058c2ecf20Sopenharmony_ci		mount = strtok(NULL, delim);
2068c2ecf20Sopenharmony_ci		type = strtok(NULL, delim);
2078c2ecf20Sopenharmony_ci		strtok(NULL, delim);
2088c2ecf20Sopenharmony_ci		strtok(NULL, delim);
2098c2ecf20Sopenharmony_ci		strtok(NULL, delim);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		if (strcmp(type, "cgroup2") == 0) {
2128c2ecf20Sopenharmony_ci			strncpy(root, mount, len);
2138c2ecf20Sopenharmony_ci			return 0;
2148c2ecf20Sopenharmony_ci		}
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return -1;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ciint cg_create(const char *cgroup)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	return mkdir(cgroup, 0755);
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ciint cg_wait_for_proc_count(const char *cgroup, int count)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	char buf[10 * PAGE_SIZE] = {0};
2288c2ecf20Sopenharmony_ci	int attempts;
2298c2ecf20Sopenharmony_ci	char *ptr;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	for (attempts = 10; attempts >= 0; attempts--) {
2328c2ecf20Sopenharmony_ci		int nr = 0;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		if (cg_read(cgroup, "cgroup.procs", buf, sizeof(buf)))
2358c2ecf20Sopenharmony_ci			break;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		for (ptr = buf; *ptr; ptr++)
2388c2ecf20Sopenharmony_ci			if (*ptr == '\n')
2398c2ecf20Sopenharmony_ci				nr++;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		if (nr >= count)
2428c2ecf20Sopenharmony_ci			return 0;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		usleep(100000);
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return -1;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ciint cg_killall(const char *cgroup)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	char buf[PAGE_SIZE];
2538c2ecf20Sopenharmony_ci	char *ptr = buf;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (cg_read(cgroup, "cgroup.procs", buf, sizeof(buf)))
2568c2ecf20Sopenharmony_ci		return -1;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	while (ptr < buf + sizeof(buf)) {
2598c2ecf20Sopenharmony_ci		int pid = strtol(ptr, &ptr, 10);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		if (pid == 0)
2628c2ecf20Sopenharmony_ci			break;
2638c2ecf20Sopenharmony_ci		if (*ptr)
2648c2ecf20Sopenharmony_ci			ptr++;
2658c2ecf20Sopenharmony_ci		else
2668c2ecf20Sopenharmony_ci			break;
2678c2ecf20Sopenharmony_ci		if (kill(pid, SIGKILL))
2688c2ecf20Sopenharmony_ci			return -1;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	return 0;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ciint cg_destroy(const char *cgroup)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	int ret;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ciretry:
2798c2ecf20Sopenharmony_ci	ret = rmdir(cgroup);
2808c2ecf20Sopenharmony_ci	if (ret && errno == EBUSY) {
2818c2ecf20Sopenharmony_ci		cg_killall(cgroup);
2828c2ecf20Sopenharmony_ci		usleep(100);
2838c2ecf20Sopenharmony_ci		goto retry;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (ret && errno == ENOENT)
2878c2ecf20Sopenharmony_ci		ret = 0;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return ret;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ciint cg_enter(const char *cgroup, int pid)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	char pidbuf[64];
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	snprintf(pidbuf, sizeof(pidbuf), "%d", pid);
2978c2ecf20Sopenharmony_ci	return cg_write(cgroup, "cgroup.procs", pidbuf);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ciint cg_enter_current(const char *cgroup)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	return cg_write(cgroup, "cgroup.procs", "0");
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ciint cg_enter_current_thread(const char *cgroup)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	return cg_write(cgroup, "cgroup.threads", "0");
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ciint cg_run(const char *cgroup,
3118c2ecf20Sopenharmony_ci	   int (*fn)(const char *cgroup, void *arg),
3128c2ecf20Sopenharmony_ci	   void *arg)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	int pid, retcode;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	pid = fork();
3178c2ecf20Sopenharmony_ci	if (pid < 0) {
3188c2ecf20Sopenharmony_ci		return pid;
3198c2ecf20Sopenharmony_ci	} else if (pid == 0) {
3208c2ecf20Sopenharmony_ci		char buf[64];
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		snprintf(buf, sizeof(buf), "%d", getpid());
3238c2ecf20Sopenharmony_ci		if (cg_write(cgroup, "cgroup.procs", buf))
3248c2ecf20Sopenharmony_ci			exit(EXIT_FAILURE);
3258c2ecf20Sopenharmony_ci		exit(fn(cgroup, arg));
3268c2ecf20Sopenharmony_ci	} else {
3278c2ecf20Sopenharmony_ci		waitpid(pid, &retcode, 0);
3288c2ecf20Sopenharmony_ci		if (WIFEXITED(retcode))
3298c2ecf20Sopenharmony_ci			return WEXITSTATUS(retcode);
3308c2ecf20Sopenharmony_ci		else
3318c2ecf20Sopenharmony_ci			return -1;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cipid_t clone_into_cgroup(int cgroup_fd)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci#ifdef CLONE_ARGS_SIZE_VER2
3388c2ecf20Sopenharmony_ci	pid_t pid;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	struct __clone_args args = {
3418c2ecf20Sopenharmony_ci		.flags = CLONE_INTO_CGROUP,
3428c2ecf20Sopenharmony_ci		.exit_signal = SIGCHLD,
3438c2ecf20Sopenharmony_ci		.cgroup = cgroup_fd,
3448c2ecf20Sopenharmony_ci	};
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	pid = sys_clone3(&args, sizeof(struct __clone_args));
3478c2ecf20Sopenharmony_ci	/*
3488c2ecf20Sopenharmony_ci	 * Verify that this is a genuine test failure:
3498c2ecf20Sopenharmony_ci	 * ENOSYS -> clone3() not available
3508c2ecf20Sopenharmony_ci	 * E2BIG  -> CLONE_INTO_CGROUP not available
3518c2ecf20Sopenharmony_ci	 */
3528c2ecf20Sopenharmony_ci	if (pid < 0 && (errno == ENOSYS || errno == E2BIG))
3538c2ecf20Sopenharmony_ci		goto pretend_enosys;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return pid;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cipretend_enosys:
3588c2ecf20Sopenharmony_ci#endif
3598c2ecf20Sopenharmony_ci	errno = ENOSYS;
3608c2ecf20Sopenharmony_ci	return -ENOSYS;
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ciint clone_reap(pid_t pid, int options)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	int ret;
3668c2ecf20Sopenharmony_ci	siginfo_t info = {
3678c2ecf20Sopenharmony_ci		.si_signo = 0,
3688c2ecf20Sopenharmony_ci	};
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ciagain:
3718c2ecf20Sopenharmony_ci	ret = waitid(P_PID, pid, &info, options | __WALL | __WNOTHREAD);
3728c2ecf20Sopenharmony_ci	if (ret < 0) {
3738c2ecf20Sopenharmony_ci		if (errno == EINTR)
3748c2ecf20Sopenharmony_ci			goto again;
3758c2ecf20Sopenharmony_ci		return -1;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (options & WEXITED) {
3798c2ecf20Sopenharmony_ci		if (WIFEXITED(info.si_status))
3808c2ecf20Sopenharmony_ci			return WEXITSTATUS(info.si_status);
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (options & WSTOPPED) {
3848c2ecf20Sopenharmony_ci		if (WIFSTOPPED(info.si_status))
3858c2ecf20Sopenharmony_ci			return WSTOPSIG(info.si_status);
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (options & WCONTINUED) {
3898c2ecf20Sopenharmony_ci		if (WIFCONTINUED(info.si_status))
3908c2ecf20Sopenharmony_ci			return 0;
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return -1;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ciint dirfd_open_opath(const char *dir)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	return open(dir, O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW | O_PATH);
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci#define close_prot_errno(fd)                                                   \
4028c2ecf20Sopenharmony_ci	if (fd >= 0) {                                                         \
4038c2ecf20Sopenharmony_ci		int _e_ = errno;                                               \
4048c2ecf20Sopenharmony_ci		close(fd);                                                     \
4058c2ecf20Sopenharmony_ci		errno = _e_;                                                   \
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic int clone_into_cgroup_run_nowait(const char *cgroup,
4098c2ecf20Sopenharmony_ci					int (*fn)(const char *cgroup, void *arg),
4108c2ecf20Sopenharmony_ci					void *arg)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	int cgroup_fd;
4138c2ecf20Sopenharmony_ci	pid_t pid;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	cgroup_fd =  dirfd_open_opath(cgroup);
4168c2ecf20Sopenharmony_ci	if (cgroup_fd < 0)
4178c2ecf20Sopenharmony_ci		return -1;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	pid = clone_into_cgroup(cgroup_fd);
4208c2ecf20Sopenharmony_ci	close_prot_errno(cgroup_fd);
4218c2ecf20Sopenharmony_ci	if (pid == 0)
4228c2ecf20Sopenharmony_ci		exit(fn(cgroup, arg));
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	return pid;
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ciint cg_run_nowait(const char *cgroup,
4288c2ecf20Sopenharmony_ci		  int (*fn)(const char *cgroup, void *arg),
4298c2ecf20Sopenharmony_ci		  void *arg)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	int pid;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	pid = clone_into_cgroup_run_nowait(cgroup, fn, arg);
4348c2ecf20Sopenharmony_ci	if (pid > 0)
4358c2ecf20Sopenharmony_ci		return pid;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	/* Genuine test failure. */
4388c2ecf20Sopenharmony_ci	if (pid < 0 && errno != ENOSYS)
4398c2ecf20Sopenharmony_ci		return -1;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	pid = fork();
4428c2ecf20Sopenharmony_ci	if (pid == 0) {
4438c2ecf20Sopenharmony_ci		char buf[64];
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		snprintf(buf, sizeof(buf), "%d", getpid());
4468c2ecf20Sopenharmony_ci		if (cg_write(cgroup, "cgroup.procs", buf))
4478c2ecf20Sopenharmony_ci			exit(EXIT_FAILURE);
4488c2ecf20Sopenharmony_ci		exit(fn(cgroup, arg));
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	return pid;
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ciint get_temp_fd(void)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	return open(".", O_TMPFILE | O_RDWR | O_EXCL);
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ciint alloc_pagecache(int fd, size_t size)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	char buf[PAGE_SIZE];
4628c2ecf20Sopenharmony_ci	struct stat st;
4638c2ecf20Sopenharmony_ci	int i;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	if (fstat(fd, &st))
4668c2ecf20Sopenharmony_ci		goto cleanup;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	size += st.st_size;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	if (ftruncate(fd, size))
4718c2ecf20Sopenharmony_ci		goto cleanup;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	for (i = 0; i < size; i += sizeof(buf))
4748c2ecf20Sopenharmony_ci		read(fd, buf, sizeof(buf));
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	return 0;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cicleanup:
4798c2ecf20Sopenharmony_ci	return -1;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ciint alloc_anon(const char *cgroup, void *arg)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	size_t size = (unsigned long)arg;
4858c2ecf20Sopenharmony_ci	char *buf, *ptr;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	buf = malloc(size);
4888c2ecf20Sopenharmony_ci	for (ptr = buf; ptr < buf + size; ptr += PAGE_SIZE)
4898c2ecf20Sopenharmony_ci		*ptr = 0;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	free(buf);
4928c2ecf20Sopenharmony_ci	return 0;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ciint is_swap_enabled(void)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	char buf[PAGE_SIZE];
4988c2ecf20Sopenharmony_ci	const char delim[] = "\n";
4998c2ecf20Sopenharmony_ci	int cnt = 0;
5008c2ecf20Sopenharmony_ci	char *line;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	if (read_text("/proc/swaps", buf, sizeof(buf)) <= 0)
5038c2ecf20Sopenharmony_ci		return -1;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	for (line = strtok(buf, delim); line; line = strtok(NULL, delim))
5068c2ecf20Sopenharmony_ci		cnt++;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	return cnt > 1;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ciint set_oom_adj_score(int pid, int score)
5128c2ecf20Sopenharmony_ci{
5138c2ecf20Sopenharmony_ci	char path[PATH_MAX];
5148c2ecf20Sopenharmony_ci	int fd, len;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	sprintf(path, "/proc/%d/oom_score_adj", pid);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	fd = open(path, O_WRONLY | O_APPEND);
5198c2ecf20Sopenharmony_ci	if (fd < 0)
5208c2ecf20Sopenharmony_ci		return fd;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	len = dprintf(fd, "%d", score);
5238c2ecf20Sopenharmony_ci	if (len < 0) {
5248c2ecf20Sopenharmony_ci		close(fd);
5258c2ecf20Sopenharmony_ci		return len;
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	close(fd);
5298c2ecf20Sopenharmony_ci	return 0;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cissize_t proc_read_text(int pid, bool thread, const char *item, char *buf, size_t size)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	char path[PATH_MAX];
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	if (!pid)
5378c2ecf20Sopenharmony_ci		snprintf(path, sizeof(path), "/proc/%s/%s",
5388c2ecf20Sopenharmony_ci			 thread ? "thread-self" : "self", item);
5398c2ecf20Sopenharmony_ci	else
5408c2ecf20Sopenharmony_ci		snprintf(path, sizeof(path), "/proc/%d/%s", pid, item);
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	return read_text(path, buf, size);
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ciint proc_read_strstr(int pid, bool thread, const char *item, const char *needle)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	char buf[PAGE_SIZE];
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (proc_read_text(pid, thread, item, buf, sizeof(buf)) < 0)
5508c2ecf20Sopenharmony_ci		return -1;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	return strstr(buf, needle) ? 0 : -1;
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ciint clone_into_cgroup_run_wait(const char *cgroup)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	int cgroup_fd;
5588c2ecf20Sopenharmony_ci	pid_t pid;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	cgroup_fd =  dirfd_open_opath(cgroup);
5618c2ecf20Sopenharmony_ci	if (cgroup_fd < 0)
5628c2ecf20Sopenharmony_ci		return -1;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	pid = clone_into_cgroup(cgroup_fd);
5658c2ecf20Sopenharmony_ci	close_prot_errno(cgroup_fd);
5668c2ecf20Sopenharmony_ci	if (pid < 0)
5678c2ecf20Sopenharmony_ci		return -1;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (pid == 0)
5708c2ecf20Sopenharmony_ci		exit(EXIT_SUCCESS);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	/*
5738c2ecf20Sopenharmony_ci	 * We don't care whether this fails. We only care whether the initial
5748c2ecf20Sopenharmony_ci	 * clone succeeded.
5758c2ecf20Sopenharmony_ci	 */
5768c2ecf20Sopenharmony_ci	(void)clone_reap(pid, WEXITED);
5778c2ecf20Sopenharmony_ci	return 0;
5788c2ecf20Sopenharmony_ci}
579