cgroup.c 2.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// SPDX-License-Identifier: GPL-2.0
#include <linux/stringify.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fs.h"

11 12 13 14 15 16 17 18
struct cgroupfs_cache_entry {
	char	subsys[32];
	char	mountpoint[PATH_MAX];
};

/* just cache last used one */
static struct cgroupfs_cache_entry cached;

19 20 21
int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys)
{
	FILE *fp;
22 23 24 25
	char *line = NULL;
	size_t len = 0;
	char *p, *path;
	char mountpoint[PATH_MAX];
26

27 28 29 30 31 32 33 34
	if (!strcmp(cached.subsys, subsys)) {
		if (strlen(cached.mountpoint) < maxlen) {
			strcpy(buf, cached.mountpoint);
			return 0;
		}
		return -1;
	}

35 36 37 38 39 40 41
	fp = fopen("/proc/mounts", "r");
	if (!fp)
		return -1;

	/*
	 * in order to handle split hierarchy, we need to scan /proc/mounts
	 * and inspect every cgroupfs mount point to find one that has
42 43
	 * the given subsystem.  If we found v1, just use it.  If not we can
	 * use v2 path as a fallback.
44
	 */
45
	mountpoint[0] = '\0';
46

47 48 49 50 51 52 53 54 55 56 57
	/*
	 * The /proc/mounts has the follow format:
	 *
	 *   <devname> <mount point> <fs type> <options> ...
	 *
	 */
	while (getline(&line, &len, fp) != -1) {
		/* skip devname */
		p = strchr(line, ' ');
		if (p == NULL)
			continue;
58

59 60 61 62 63
		/* save the mount point */
		path = ++p;
		p = strchr(p, ' ');
		if (p == NULL)
			continue;
64

65
		*p++ = '\0';
66

67 68 69
		/* check filesystem type */
		if (strncmp(p, "cgroup", 6))
			continue;
70

71 72 73 74
		if (p[6] == '2') {
			/* save cgroup v2 path */
			strcpy(mountpoint, path);
			continue;
75 76
		}

77 78 79 80 81 82 83 84 85 86 87 88 89
		/* now we have cgroup v1, check the options for subsystem */
		p += 7;

		p = strstr(p, subsys);
		if (p == NULL)
			continue;

		/* sanity check: it should be separated by a space or a comma */
		if (!strchr(" ,", p[-1]) || !strchr(" ,", p[strlen(subsys)]))
			continue;

		strcpy(mountpoint, path);
		break;
90
	}
91
	free(line);
92 93
	fclose(fp);

94 95 96
	strncpy(cached.subsys, subsys, sizeof(cached.subsys) - 1);
	strcpy(cached.mountpoint, mountpoint);

97 98
	if (mountpoint[0] && strlen(mountpoint) < maxlen) {
		strcpy(buf, mountpoint);
99 100 101 102
		return 0;
	}
	return -1;
}