108 lines · c
1// SPDX-License-Identifier: GPL-2.02#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 11struct cgroupfs_cache_entry {12 char subsys[32];13 char mountpoint[PATH_MAX];14};15 16/* just cache last used one */17static struct cgroupfs_cache_entry *cached;18 19int 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/mounts41 * and inspect every cgroupfs mount point to find one that has42 * the given subsystem. If we found v1, just use it. If not we can43 * 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