2023-08-30 17:31:07 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <linux/stringify.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "fs.h"
|
|
|
|
|
|
|
|
struct cgroupfs_cache_entry {
|
|
|
|
char subsys[32];
|
|
|
|
char mountpoint[PATH_MAX];
|
|
|
|
};
|
|
|
|
|
|
|
|
/* just cache last used one */
|
2023-10-24 12:59:35 +02:00
|
|
|
static struct cgroupfs_cache_entry *cached;
|
2023-08-30 17:31:07 +02:00
|
|
|
|
|
|
|
int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
char *line = NULL;
|
|
|
|
size_t len = 0;
|
|
|
|
char *p, *path;
|
|
|
|
char mountpoint[PATH_MAX];
|
|
|
|
|
2023-10-24 12:59:35 +02:00
|
|
|
if (cached && !strcmp(cached->subsys, subsys)) {
|
|
|
|
if (strlen(cached->mountpoint) < maxlen) {
|
|
|
|
strcpy(buf, cached->mountpoint);
|
2023-08-30 17:31:07 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fp = fopen("/proc/mounts", "r");
|
|
|
|
if (!fp)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* in order to handle split hierarchy, we need to scan /proc/mounts
|
|
|
|
* and inspect every cgroupfs mount point to find one that has
|
|
|
|
* the given subsystem. If we found v1, just use it. If not we can
|
|
|
|
* use v2 path as a fallback.
|
|
|
|
*/
|
|
|
|
mountpoint[0] = '\0';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The /proc/mounts has the follow format:
|
|
|
|
*
|
|
|
|
* <devname> <mount point> <fs type> <options> ...
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
while (getline(&line, &len, fp) != -1) {
|
|
|
|
/* skip devname */
|
|
|
|
p = strchr(line, ' ');
|
|
|
|
if (p == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* save the mount point */
|
|
|
|
path = ++p;
|
|
|
|
p = strchr(p, ' ');
|
|
|
|
if (p == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
*p++ = '\0';
|
|
|
|
|
|
|
|
/* check filesystem type */
|
|
|
|
if (strncmp(p, "cgroup", 6))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (p[6] == '2') {
|
|
|
|
/* save cgroup v2 path */
|
|
|
|
strcpy(mountpoint, path);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now we have cgroup v1, check the options for subsystem */
|
|
|
|
p += 7;
|
|
|
|
|
|
|
|
p = strstr(p, subsys);
|
|
|
|
if (p == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* sanity check: it should be separated by a space or a comma */
|
|
|
|
if (!strchr(" ,", p[-1]) || !strchr(" ,", p[strlen(subsys)]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
strcpy(mountpoint, path);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free(line);
|
|
|
|
fclose(fp);
|
|
|
|
|
2023-10-24 12:59:35 +02:00
|
|
|
if (!cached)
|
|
|
|
cached = calloc(1, sizeof(*cached));
|
|
|
|
|
|
|
|
if (cached) {
|
|
|
|
strncpy(cached->subsys, subsys, sizeof(cached->subsys) - 1);
|
|
|
|
strcpy(cached->mountpoint, mountpoint);
|
|
|
|
}
|
2023-08-30 17:31:07 +02:00
|
|
|
|
|
|
|
if (mountpoint[0] && strlen(mountpoint) < maxlen) {
|
|
|
|
strcpy(buf, mountpoint);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|