#include <sys/stat.h>
//#include <sys/statfs.h>
#include <sys/types.h>
+#include <sys/xattr.h>
#include <unistd.h>
#include "alloc-util.h"
#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
-#include "formats-util.h"
+#include "format-util.h"
#include "fs-util.h"
//#include "log.h"
#include "login-util.h"
if (de->d_type != DT_DIR)
continue;
- if (streq(de->d_name, ".") ||
- streq(de->d_name, ".."))
+ if (dot_or_dot_dot(de->d_name))
continue;
b = strdup(de->d_name);
while ((r = cg_read_subgroup(d, &fn)) > 0) {
_cleanup_free_ char *p = NULL;
- p = strjoin(path, "/", fn, NULL);
+ p = strjoin(path, "/", fn);
free(fn);
if (!p)
return -ENOMEM;
while ((r = cg_read_subgroup(d, &fn)) > 0) {
_cleanup_free_ char *p = NULL;
- p = strjoin(pfrom, "/", fn, NULL);
+ p = strjoin(pfrom, "/", fn);
free(fn);
if (!p)
return -ENOMEM;
if (isempty(path) && isempty(suffix))
t = strappend("/sys/fs/cgroup/", dn);
else if (isempty(path))
- t = strjoin("/sys/fs/cgroup/", dn, "/", suffix, NULL);
+ t = strjoin("/sys/fs/cgroup/", dn, "/", suffix);
else if (isempty(suffix))
- t = strjoin("/sys/fs/cgroup/", dn, "/", path, NULL);
+ t = strjoin("/sys/fs/cgroup/", dn, "/", path);
else
- t = strjoin("/sys/fs/cgroup/", dn, "/", path, "/", suffix, NULL);
+ t = strjoin("/sys/fs/cgroup/", dn, "/", path, "/", suffix);
if (!t)
return -ENOMEM;
else if (isempty(suffix))
t = strappend("/sys/fs/cgroup/", path);
else
- t = strjoin("/sys/fs/cgroup/", path, "/", suffix, NULL);
+ t = strjoin("/sys/fs/cgroup/", path, "/", suffix);
if (!t)
return -ENOMEM;
else if (!path)
t = strdup(suffix);
else
- t = strjoin(path, "/", suffix, NULL);
+ t = strjoin(path, "/", suffix);
if (!t)
return -ENOMEM;
if (!cg_controller_is_valid(controller))
return -EINVAL;
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (!cg_controller_is_valid(controller))
return -EINVAL;
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0) {
if (r < 0)
return r;
- unified = cg_unified();
+ unified = cg_unified(controller);
if (unified < 0)
return unified;
if (unified)
return 0;
}
+
+int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags) {
+ _cleanup_free_ char *fs = NULL;
+ int r;
+
+ assert(path);
+ assert(name);
+ assert(value || size <= 0);
+
+ r = cg_get_path(controller, path, NULL, &fs);
+ if (r < 0)
+ return r;
+
+ if (setxattr(fs, name, value, size, flags) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size) {
+ _cleanup_free_ char *fs = NULL;
+ ssize_t n;
+ int r;
+
+ assert(path);
+ assert(name);
+
+ r = cg_get_path(controller, path, NULL, &fs);
+ if (r < 0)
+ return r;
+
+ n = getxattr(fs, name, value, size);
+ if (n < 0)
+ return -errno;
+
+ return (int) n;
+}
#endif // 0
int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
assert(path);
assert(pid >= 0);
- unified = cg_unified();
+ if (controller) {
+ if (!cg_controller_is_valid(controller))
+ return -EINVAL;
+ } else
+ controller = SYSTEMD_CGROUP_CONTROLLER;
+
+ unified = cg_unified(controller);
if (unified < 0)
return unified;
- if (unified == 0) {
- if (controller) {
- if (!cg_controller_is_valid(controller))
- return -EINVAL;
- } else
- controller = SYSTEMD_CGROUP_CONTROLLER;
-
+ if (unified == 0)
cs = strlen(controller);
- }
fs = procfs_file_alloca(pid, "cgroup");
log_debug_elogind("Searching for PID %u in \"%s\" (controller \"%s\")",
assert(agent);
- unified = cg_unified();
+ unified = cg_unified(controller);
if (unified < 0)
return unified;
if (unified) /* doesn't apply to unified hierarchy */
_cleanup_free_ char *fs = NULL;
int r, unified;
- unified = cg_unified();
+ unified = cg_unified(controller);
if (unified < 0)
return unified;
if (unified) /* Doesn't apply to unified hierarchy */
if (controller && (isempty(path) || path_equal(path, "/")))
return false;
- unified = cg_unified();
+ unified = cg_unified(controller);
if (unified < 0)
return unified;
while ((r = cg_read_subgroup(d, &fn)) > 0) {
_cleanup_free_ char *p = NULL;
- p = strjoin(path, "/", fn, NULL);
+ p = strjoin(path, "/", fn);
free(fn);
if (!p)
return -ENOMEM;
}
p = path_startswith(cgroup, root);
+#if 0 /// With other controllers, elogind might end up in /elogind, and *p is 0
if (p && p > cgroup)
+#else
+ if (p && p[0] && (p > cgroup))
+#endif // 0
*shifted = p - 1;
else
*shifted = cgroup;
if (!e) {
char *s;
- s = strdup("-.slice");
+ s = strdup(SPECIAL_ROOT_SLICE);
if (!s)
return -ENOMEM;
assert(unit);
assert(ret);
- if (streq(unit, "-.slice")) {
+ if (streq(unit, SPECIAL_ROOT_SLICE)) {
char *x;
x = strdup("");
return r;
/* If we are in the unified hierarchy, we are done now */
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0)
if (r < 0)
return r;
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0)
return r;
}
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0)
if (r < 0)
return r;
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0)
* includes controllers we can make sense of and that are
* actually accessible. */
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (unified > 0) {
}
#endif // 0
-static thread_local int unified_cache = -1;
+static thread_local CGroupUnified unified_cache = CGROUP_UNIFIED_UNKNOWN;
+
+static int cg_update_unified(void) {
-int cg_unified(void) {
struct statfs fs;
/* Checks if we support the unified hierarchy. Returns an
* have any other trouble determining if the unified hierarchy
* is supported. */
- if (unified_cache >= 0)
- return unified_cache;
+ if (unified_cache >= CGROUP_UNIFIED_NONE)
+ return 0;
if (statfs("/sys/fs/cgroup/", &fs) < 0)
return -errno;
#if 0 /// UNNEEDED by elogind
if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC))
- unified_cache = true;
- else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC))
+ unified_cache = CGROUP_UNIFIED_ALL;
+ else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) {
+ if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0)
+ return -errno;
+
+ unified_cache = F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC) ?
+ CGROUP_UNIFIED_SYSTEMD : CGROUP_UNIFIED_NONE;
+ } else
+ return -ENOMEDIUM;
#else
/* elogind can not support the unified hierarchy as a controller,
* so always assume a classical hierarchy.
* If, and only *if*, someone really wants to substitute systemd-login
* in an environment managed by systemd with elogind, we might have to
* add such a support. */
- if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC))
+ unified_cache = CGROUP_UNIFIED_NONE;
#endif // 0
- unified_cache = false;
+
+ return 0;
+}
+
+int cg_unified(const char *controller) {
+
+ int r;
+
+ r = cg_update_unified();
+ if (r < 0)
+ return r;
+
+ if (streq_ptr(controller, SYSTEMD_CGROUP_CONTROLLER))
+ return unified_cache >= CGROUP_UNIFIED_SYSTEMD;
else
- return -ENOMEDIUM;
+ return unified_cache >= CGROUP_UNIFIED_ALL;
+}
+
+int cg_all_unified(void) {
- return unified_cache;
+ return cg_unified(NULL);
}
#if 0 /// UNNEEDED by elogind
void cg_unified_flush(void) {
- unified_cache = -1;
+ unified_cache = CGROUP_UNIFIED_UNKNOWN;
}
int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
if (supported == 0)
return 0;
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified < 0)
return unified;
if (!unified) /* on the legacy hiearchy there's no joining of controllers defined */
bool cg_is_unified_wanted(void) {
static thread_local int wanted = -1;
int r, unified;
+ bool b;
/* If the hierarchy is already mounted, then follow whatever
* was chosen for it. */
- unified = cg_unified();
+ unified = cg_all_unified();
if (unified >= 0)
return unified;
if (wanted >= 0)
return wanted;
- r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy", NULL);
- if (r > 0)
- return (wanted = true);
- else {
- _cleanup_free_ char *value = NULL;
-
- r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy=", &value);
- if (r < 0)
- return false;
- if (r == 0)
- return (wanted = false);
+ r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", &b);
+ if (r < 0)
+ return false;
- return (wanted = parse_boolean(value) > 0);
- }
+ return (wanted = r > 0 ? b : false);
}
bool cg_is_legacy_wanted(void) {
return !cg_is_unified_wanted();
}
+
+bool cg_is_unified_systemd_controller_wanted(void) {
+ static thread_local int wanted = -1;
+ int r, unified;
+ bool b;
+
+ /* If the unified hierarchy is requested in full, no need to
+ * bother with this. */
+ if (cg_is_unified_wanted())
+ return 0;
+
+ /* If the hierarchy is already mounted, then follow whatever
+ * was chosen for it. */
+ unified = cg_unified(SYSTEMD_CGROUP_CONTROLLER);
+ if (unified >= 0)
+ return unified;
+
+ /* Otherwise, let's see what the kernel command line has to
+ * say. Since checking that is expensive, let's cache the
+ * result. */
+ if (wanted >= 0)
+ return wanted;
+
+ r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", &b);
+ if (r < 0)
+ return false;
+
#else
bool cg_is_legacy_wanted(void) {
return true;
+ /* The meaning of the kernel option is reversed wrt. to the return value
+ * of this function, hence the negation. */
+ return (wanted = r > 0 ? !b : false);
+ return (wanted = r > 0 ? b : false);
+}
+
+bool cg_is_legacy_systemd_controller_wanted(void) {
+ return cg_is_legacy_wanted() && !cg_is_unified_systemd_controller_wanted();
}
#endif // 0
}
#endif // 0
+bool is_cgroup_fs(const struct statfs *s) {
+ return is_fs_type(s, CGROUP_SUPER_MAGIC) ||
+ is_fs_type(s, CGROUP2_SUPER_MAGIC);
+}
+
+bool fd_is_cgroup_fs(int fd) {
+ struct statfs s;
+
+ if (fstatfs(fd, &s) < 0)
+ return -errno;
+
+ return is_cgroup_fs(&s);
+}
+
static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
[CGROUP_CONTROLLER_CPU] = "cpu",
[CGROUP_CONTROLLER_CPUACCT] = "cpuacct",