int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
const char *p;
- char *mp;
- int r;
+ char *t;
+ static __thread bool good = false;
assert(controller);
assert(fs);
+ if (_unlikely_(!good)) {
+ int r;
+
+ r = path_is_mount_point("/sys/fs/cgroup");
+ if (r <= 0)
+ return r < 0 ? r : -ENOENT;
+
+ /* Cache this to save a few stat()s */
+ good = true;
+ }
+
+ if (isempty(controller))
+ return -EINVAL;
+
/* This is a very minimal lookup from controller names to
* paths. Since we have mounted most hierarchies ourselves
* should be kinda safe, but eventually we might want to
else
p = controller;
- if (asprintf(&mp, "/sys/fs/cgroup/%s", p) < 0)
- return -ENOMEM;
-
- if ((r = path_is_mount_point(mp)) <= 0) {
- free(mp);
- return r < 0 ? r : -ENOENT;
- }
-
if (path && suffix)
- r = asprintf(fs, "%s/%s/%s", mp, path, suffix);
+ t = join("/sys/fs/cgroup/", p, "/", path, "/", suffix, NULL);
else if (path)
- r = asprintf(fs, "%s/%s", mp, path);
+ t = join("/sys/fs/cgroup/", p, "/", path, NULL);
else if (suffix)
- r = asprintf(fs, "%s/%s", mp, suffix);
- else {
- path_kill_slashes(mp);
- *fs = mp;
- return 0;
- }
+ t = join("/sys/fs/cgroup/", p, "/", suffix, NULL);
+ else
+ t = join("/sys/fs/cgroup/", p, NULL);
- free(mp);
- path_kill_slashes(*fs);
- return r < 0 ? -ENOMEM : 0;
+ if (!t)
+ return -ENOMEM;
+
+ path_kill_slashes(t);
+
+ *fs = t;
+ return 0;
}
int cg_trim(const char *controller, const char *path, bool delete_root) {
return r;
}
+
+int cg_get_user_path(char **path) {
+ char *root, *p;
+
+ assert(path);
+
+ /* Figure out the place to put user cgroups below. We use the
+ * same as PID 1 has but with the "/system" suffix replaced by
+ * "/user" */
+
+ if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0)
+ p = strdup("/user");
+ else {
+ if (endswith(root, "/system"))
+ root[strlen(root) - 7] = 0;
+ else if (streq(root, "/"))
+ root[0] = 0;
+
+ p = strappend(root, "/user");
+ free(root);
+ }
+
+ if (!p)
+ return -ENOMEM;
+
+ *path = p;
+ return 0;
+}