linux/tools/lib/api/fs/cgroup.c
<<
>>
Prefs
   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
  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 (!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        strncpy(cached.subsys, subsys, sizeof(cached.subsys) - 1);
  95        strcpy(cached.mountpoint, mountpoint);
  96
  97        if (mountpoint[0] && strlen(mountpoint) < maxlen) {
  98                strcpy(buf, mountpoint);
  99                return 0;
 100        }
 101        return -1;
 102}
 103