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 struct cgroupfs_cache_entry { 12 char subsys[32]; 13 char mountpoint[PATH_MAX]; 14 }; 15 16 /* just cache last used one */ 17 static struct cgroupfs_cache_entry *cached; 18 19 int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys) 20 { 21 FILE *fp; 22 char *line = NULL; 23 size_t len = 0; 24 char *p, *path; 25 char mountpoint[PATH_MAX]; 26 27 if (cached && !strcmp(cached->subsys, subsys)) { 28 if (strlen(cached->mountpoint) < maxlen) { 29 strcpy(buf, cached->mountpoint); 30 return 0; 31 } 32 return -1; 33 } 34 35 fp = fopen("/proc/mounts", "r"); 36 if (!fp) 37 return -1; 38 39 /* 40 * in order to handle split hierarchy, we need to scan /proc/mounts 41 * and inspect every cgroupfs mount point to find one that has 42 * the given subsystem. If we found v1, just use it. If not we can 43 * use v2 path as a fallback. 44 */ 45 mountpoint[0] = '\0'; 46 47 /* 48 * The /proc/mounts has the follow format: 49 * 50 * <devname> <mount point> <fs type> <options> ... 51 * 52 */ 53 while (getline(&line, &len, fp) != -1) { 54 /* skip devname */ 55 p = strchr(line, ' '); 56 if (p == NULL) 57 continue; 58 59 /* save the mount point */ 60 path = ++p; 61 p = strchr(p, ' '); 62 if (p == NULL) 63 continue; 64 65 *p++ = '\0'; 66 67 /* check filesystem type */ 68 if (strncmp(p, "cgroup", 6)) 69 continue; 70 71 if (p[6] == '2') { 72 /* save cgroup v2 path */ 73 strcpy(mountpoint, path); 74 continue; 75 } 76 77 /* now we have cgroup v1, check the options for subsystem */ 78 p += 7; 79 80 p = strstr(p, subsys); 81 if (p == NULL) 82 continue; 83 84 /* sanity check: it should be separated by a space or a comma */ 85 if (!strchr(" ,", p[-1]) || !strchr(" ,", p[strlen(subsys)])) 86 continue; 87 88 strcpy(mountpoint, path); 89 break; 90 } 91 free(line); 92 fclose(fp); 93 94 if (!cached) 95 cached = calloc(1, sizeof(*cached)); 96 97 if (cached) { 98 strncpy(cached->subsys, subsys, sizeof(cached->subsys) - 1); 99 strcpy(cached->mountpoint, mountpoint); 100 } 101 102 if (mountpoint[0] && strlen(mountpoint) < maxlen) { 103 strcpy(buf, mountpoint); 104 return 0; 105 } 106 return -1; 107 } 108