#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "strv.h"
#include "unit-name.h"
#include "user-util.h"
return 1;
}
-int cg_read_event(const char *controller, const char *path, const char *event,
- char **val)
-{
+int cg_read_event(
+ const char *controller,
+ const char *path,
+ const char *event,
+ char **val) {
+
_cleanup_free_ char *events = NULL, *content = NULL;
char *p, *line;
int r;
return -ENOMEM;
}
- my_pid = getpid();
+ my_pid = getpid_cached();
do {
_cleanup_fclose_ FILE *f = NULL;
if (!s)
return -ENOMEM;
- my_pid = getpid();
+ my_pid = getpid_cached();
do {
_cleanup_fclose_ FILE *f = NULL;
return r;
if (pid == 0)
- pid = getpid();
+ pid = getpid_cached();
xsprintf(c, PID_FMT "\n", pid);
if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
r = cg_attach(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, pid);
if (r < 0)
- log_warning_errno(r, "Failed to attach %d to compat systemd cgroup %s: %m", pid, path);
+ log_warning_errno(r, "Failed to attach "PID_FMT" to compat systemd cgroup %s: %m", pid, path);
}
return 0;
if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
if (r < 0)
- log_warning_errno(r, "Failed to set group access on compat systemd cgroup %s: %m", path);
+ log_debug_errno(r, "Failed to set group access on compatibility systemd cgroup %s, ignoring: %m", path);
}
return 0;
uid_t uid,
gid_t gid) {
- _cleanup_free_ char *fs = NULL, *procs = NULL;
+ _cleanup_free_ char *fs = NULL;
int r;
assert(path);
if (mode != MODE_INVALID)
mode &= 0666;
+ /* For both the legacy and unified hierarchies, "cgroup.procs" is the main entry point for PIDs */
r = cg_get_path(controller, path, "cgroup.procs", &fs);
if (r < 0)
return r;
if (r < 0)
return r;
if (r == 0) {
- /* Compatibility, Always keep values for "tasks" in sync with
- * "cgroup.procs" */
- if (cg_get_path(controller, path, "tasks", &procs) >= 0)
- (void) chmod_and_chown(procs, mode, uid, gid);
+ const char *fn;
+
+ /* Compatibility: on cgroupsv1 always keep values for the legacy files "tasks" and
+ * "cgroup.clone_children" in sync with "cgroup.procs". Since this is legacy stuff, we don't care if
+ * this fails. */
+
+ FOREACH_STRING(fn,
+ "tasks",
+ "cgroup.clone_children") {
+
+ fs = mfree(fs);
+
+ r = cg_get_path(controller, path, fn, &fs);
+ if (r < 0)
+ log_debug_errno(r, "Failed to get path for %s of %s, ignoring: %m", fn, path);
+
+ r = chmod_and_chown(fs, mode, uid, gid);
+ if (r < 0)
+ log_debug_errno(r, "Failed to to change ownership/access mode for %s of %s, ignoring: %m", fn, path);
+ }
+ } else {
+ /* On the unified controller, we want to permit subtree controllers too. */
+
+ fs = mfree(fs);
+ r = cg_get_path(controller, path, "cgroup.subtree_control", &fs);
+ if (r < 0)
+ return r;
+
+ r = chmod_and_chown(fs, mode, uid, gid);
+ if (r < 0)
+ return r;
}
r = cg_hybrid_unified();
if (r < 0)
return r;
if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
+ /* Always propagate access mode from unified to legacy controller */
+
r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
if (r < 0)
- log_warning_errno(r, "Failed to set task access on compat systemd cgroup %s: %m", path);
+ log_debug_errno(r, "Failed to set task access on compatibility systemd cgroup %s, ignoring: %m", path);
}
return 0;
return 0;
}
+int cg_mask_to_string(CGroupMask mask, char **ret) {
+ const char *controllers[_CGROUP_CONTROLLER_MAX + 1];
+ CGroupController c;
+ int i = 0;
+ char *s;
+
+ assert(ret);
+
+ if (mask == 0) {
+ *ret = NULL;
+ return 0;
+ }
+
+ for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
+
+ if (!(mask & CGROUP_CONTROLLER_TO_MASK(c)))
+ continue;
+
+ controllers[i++] = cgroup_controller_to_string(c);
+ controllers[i] = NULL;
+ }
+
+ s = strv_join((char **)controllers, NULL);
+ if (!s)
+ return -ENOMEM;
+
+ *ret = s;
+ return 0;
+}
+
+int cg_mask_from_string(const char *value, CGroupMask *mask) {
+ assert(mask);
+ assert(value);
+
+ for (;;) {
+ _cleanup_free_ char *n = NULL;
+ CGroupController v;
+ int r;
+
+ r = extract_first_word(&value, &n, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ v = cgroup_controller_from_string(n);
+ if (v < 0)
+ continue;
+
+ *mask |= CGROUP_CONTROLLER_TO_MASK(v);
+ }
+ return 0;
+}
+
int cg_mask_supported(CGroupMask *ret) {
CGroupMask mask = 0;
int r;
return r;
if (r > 0) {
_cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
- const char *c;
/* In the unified hierarchy we can read the supported
* and accessible controllers from a the top-level
if (r < 0)
return r;
- c = controllers;
- for (;;) {
- _cleanup_free_ char *n = NULL;
- CGroupController v;
-
- r = extract_first_word(&c, &n, NULL, 0);
- if (r < 0)
- return r;
- if (r == 0)
- break;
-
- v = cgroup_controller_from_string(n);
- if (v < 0)
- continue;
-
- mask |= CGROUP_CONTROLLER_TO_MASK(v);
- }
+ r = cg_mask_from_string(controllers, &mask);
+ if (r < 0)
+ return r;
/* Currently, we support the cpu, memory, io and pids
* controller in the unified hierarchy, mask
int cg_kernel_controllers(Set *controllers) {
_cleanup_fclose_ FILE *f = NULL;
- char buf[LINE_MAX];
int r;
assert(controllers);
}
/* Ignore the header line */
- (void) fgets(buf, sizeof(buf), f);
+ (void) read_line(f, (size_t) -1, NULL);
for (;;) {
char *controller;