xref: /openbmc/linux/tools/lib/api/fs/cgroup.c (revision 7a3fb8b5)
17982a898SNamhyung Kim // SPDX-License-Identifier: GPL-2.0
27982a898SNamhyung Kim #include <linux/stringify.h>
37982a898SNamhyung Kim #include <sys/types.h>
47982a898SNamhyung Kim #include <sys/stat.h>
57982a898SNamhyung Kim #include <fcntl.h>
67982a898SNamhyung Kim #include <stdio.h>
77982a898SNamhyung Kim #include <stdlib.h>
87982a898SNamhyung Kim #include <string.h>
97982a898SNamhyung Kim #include "fs.h"
107982a898SNamhyung Kim 
1148859e52SNamhyung Kim struct cgroupfs_cache_entry {
1248859e52SNamhyung Kim 	char	subsys[32];
1348859e52SNamhyung Kim 	char	mountpoint[PATH_MAX];
1448859e52SNamhyung Kim };
1548859e52SNamhyung Kim 
1648859e52SNamhyung Kim /* just cache last used one */
17*7a3fb8b5SIan Rogers static struct cgroupfs_cache_entry *cached;
1848859e52SNamhyung Kim 
cgroupfs_find_mountpoint(char * buf,size_t maxlen,const char * subsys)197982a898SNamhyung Kim int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys)
207982a898SNamhyung Kim {
217982a898SNamhyung Kim 	FILE *fp;
226fd99b7fSNamhyung Kim 	char *line = NULL;
236fd99b7fSNamhyung Kim 	size_t len = 0;
246fd99b7fSNamhyung Kim 	char *p, *path;
256fd99b7fSNamhyung Kim 	char mountpoint[PATH_MAX];
267982a898SNamhyung Kim 
27*7a3fb8b5SIan Rogers 	if (cached && !strcmp(cached->subsys, subsys)) {
28*7a3fb8b5SIan Rogers 		if (strlen(cached->mountpoint) < maxlen) {
29*7a3fb8b5SIan Rogers 			strcpy(buf, cached->mountpoint);
3048859e52SNamhyung Kim 			return 0;
3148859e52SNamhyung Kim 		}
3248859e52SNamhyung Kim 		return -1;
3348859e52SNamhyung Kim 	}
3448859e52SNamhyung Kim 
357982a898SNamhyung Kim 	fp = fopen("/proc/mounts", "r");
367982a898SNamhyung Kim 	if (!fp)
377982a898SNamhyung Kim 		return -1;
387982a898SNamhyung Kim 
397982a898SNamhyung Kim 	/*
407982a898SNamhyung Kim 	 * in order to handle split hierarchy, we need to scan /proc/mounts
417982a898SNamhyung Kim 	 * and inspect every cgroupfs mount point to find one that has
4227ab1c1cSNamhyung Kim 	 * the given subsystem.  If we found v1, just use it.  If not we can
4327ab1c1cSNamhyung Kim 	 * use v2 path as a fallback.
447982a898SNamhyung Kim 	 */
456fd99b7fSNamhyung Kim 	mountpoint[0] = '\0';
467982a898SNamhyung Kim 
476fd99b7fSNamhyung Kim 	/*
486fd99b7fSNamhyung Kim 	 * The /proc/mounts has the follow format:
496fd99b7fSNamhyung Kim 	 *
506fd99b7fSNamhyung Kim 	 *   <devname> <mount point> <fs type> <options> ...
516fd99b7fSNamhyung Kim 	 *
526fd99b7fSNamhyung Kim 	 */
536fd99b7fSNamhyung Kim 	while (getline(&line, &len, fp) != -1) {
546fd99b7fSNamhyung Kim 		/* skip devname */
556fd99b7fSNamhyung Kim 		p = strchr(line, ' ');
566fd99b7fSNamhyung Kim 		if (p == NULL)
576fd99b7fSNamhyung Kim 			continue;
587982a898SNamhyung Kim 
596fd99b7fSNamhyung Kim 		/* save the mount point */
606fd99b7fSNamhyung Kim 		path = ++p;
616fd99b7fSNamhyung Kim 		p = strchr(p, ' ');
626fd99b7fSNamhyung Kim 		if (p == NULL)
636fd99b7fSNamhyung Kim 			continue;
647982a898SNamhyung Kim 
656fd99b7fSNamhyung Kim 		*p++ = '\0';
667982a898SNamhyung Kim 
676fd99b7fSNamhyung Kim 		/* check filesystem type */
686fd99b7fSNamhyung Kim 		if (strncmp(p, "cgroup", 6))
696fd99b7fSNamhyung Kim 			continue;
706fd99b7fSNamhyung Kim 
716fd99b7fSNamhyung Kim 		if (p[6] == '2') {
726fd99b7fSNamhyung Kim 			/* save cgroup v2 path */
736fd99b7fSNamhyung Kim 			strcpy(mountpoint, path);
746fd99b7fSNamhyung Kim 			continue;
756fd99b7fSNamhyung Kim 		}
766fd99b7fSNamhyung Kim 
776fd99b7fSNamhyung Kim 		/* now we have cgroup v1, check the options for subsystem */
786fd99b7fSNamhyung Kim 		p += 7;
796fd99b7fSNamhyung Kim 
806fd99b7fSNamhyung Kim 		p = strstr(p, subsys);
816fd99b7fSNamhyung Kim 		if (p == NULL)
826fd99b7fSNamhyung Kim 			continue;
836fd99b7fSNamhyung Kim 
846fd99b7fSNamhyung Kim 		/* sanity check: it should be separated by a space or a comma */
856fd99b7fSNamhyung Kim 		if (!strchr(" ,", p[-1]) || !strchr(" ,", p[strlen(subsys)]))
866fd99b7fSNamhyung Kim 			continue;
876fd99b7fSNamhyung Kim 
886fd99b7fSNamhyung Kim 		strcpy(mountpoint, path);
896fd99b7fSNamhyung Kim 		break;
906fd99b7fSNamhyung Kim 	}
916fd99b7fSNamhyung Kim 	free(line);
9227ab1c1cSNamhyung Kim 	fclose(fp);
9327ab1c1cSNamhyung Kim 
94*7a3fb8b5SIan Rogers 	if (!cached)
95*7a3fb8b5SIan Rogers 		cached = calloc(1, sizeof(*cached));
96*7a3fb8b5SIan Rogers 
97*7a3fb8b5SIan Rogers 	if (cached) {
98*7a3fb8b5SIan Rogers 		strncpy(cached->subsys, subsys, sizeof(cached->subsys) - 1);
99*7a3fb8b5SIan Rogers 		strcpy(cached->mountpoint, mountpoint);
100*7a3fb8b5SIan Rogers 	}
10148859e52SNamhyung Kim 
1026fd99b7fSNamhyung Kim 	if (mountpoint[0] && strlen(mountpoint) < maxlen) {
10327ab1c1cSNamhyung Kim 		strcpy(buf, mountpoint);
10427ab1c1cSNamhyung Kim 		return 0;
10527ab1c1cSNamhyung Kim 	}
10627ab1c1cSNamhyung Kim 	return -1;
1077982a898SNamhyung Kim }
108