xref: /openbmc/linux/tools/lib/api/fs/cgroup.c (revision 6fd99b7f)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/stringify.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include "fs.h"
10 
11 int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys)
12 {
13 	FILE *fp;
14 	char *line = NULL;
15 	size_t len = 0;
16 	char *p, *path;
17 	char mountpoint[PATH_MAX];
18 
19 	fp = fopen("/proc/mounts", "r");
20 	if (!fp)
21 		return -1;
22 
23 	/*
24 	 * in order to handle split hierarchy, we need to scan /proc/mounts
25 	 * and inspect every cgroupfs mount point to find one that has
26 	 * the given subsystem.  If we found v1, just use it.  If not we can
27 	 * use v2 path as a fallback.
28 	 */
29 	mountpoint[0] = '\0';
30 
31 	/*
32 	 * The /proc/mounts has the follow format:
33 	 *
34 	 *   <devname> <mount point> <fs type> <options> ...
35 	 *
36 	 */
37 	while (getline(&line, &len, fp) != -1) {
38 		/* skip devname */
39 		p = strchr(line, ' ');
40 		if (p == NULL)
41 			continue;
42 
43 		/* save the mount point */
44 		path = ++p;
45 		p = strchr(p, ' ');
46 		if (p == NULL)
47 			continue;
48 
49 		*p++ = '\0';
50 
51 		/* check filesystem type */
52 		if (strncmp(p, "cgroup", 6))
53 			continue;
54 
55 		if (p[6] == '2') {
56 			/* save cgroup v2 path */
57 			strcpy(mountpoint, path);
58 			continue;
59 		}
60 
61 		/* now we have cgroup v1, check the options for subsystem */
62 		p += 7;
63 
64 		p = strstr(p, subsys);
65 		if (p == NULL)
66 			continue;
67 
68 		/* sanity check: it should be separated by a space or a comma */
69 		if (!strchr(" ,", p[-1]) || !strchr(" ,", p[strlen(subsys)]))
70 			continue;
71 
72 		strcpy(mountpoint, path);
73 		break;
74 	}
75 	free(line);
76 	fclose(fp);
77 
78 	if (mountpoint[0] && strlen(mountpoint) < maxlen) {
79 		strcpy(buf, mountpoint);
80 		return 0;
81 	}
82 	return -1;
83 }
84