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