return 0;
}
-int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
- _cleanup_free_ char *fs = NULL;
- FILE *f;
- int r;
-
- assert(_f);
-
- r = cg_get_path(controller, path, "tasks", &fs);
- if (r < 0)
- return r;
-
- f = fopen(fs, "re");
- if (!f)
- return -errno;
-
- *_f = f;
- return 0;
-}
-
int cg_read_pid(FILE *f, pid_t *_pid) {
unsigned long ul;
return r;
if (honour_sticky) {
- char *tasks;
+ char *fn;
- /* If the sticky bit is set don't remove the directory */
+ /* If the sticky bit is set on cgroup.procs, don't
+ * remove the directory */
- tasks = strappend(p, "/tasks");
- if (!tasks)
+ fn = strappend(p, "/cgroup.procs");
+ if (!fn)
return -ENOMEM;
- r = file_is_priv_sticky(tasks);
- free(tasks);
+ r = file_is_priv_sticky(fn);
+ free(fn);
+
+ if (r > 0)
+ return 0;
+
+ /* Compatibility ... */
+ fn = strappend(p, "/tasks");
+ if (!fn)
+ return -ENOMEM;
+
+ r = file_is_priv_sticky(fn);
+ free(fn);
if (r > 0)
return 0;
pid_t pid = 0;
done = true;
- r = cg_enumerate_tasks(cfrom, pfrom, &f);
+ r = cg_enumerate_processes(cfrom, pfrom, &f);
if (r < 0) {
if (ret >= 0 && r != -ENOENT)
return r;
if (ftwbuf->level < 1)
return 0;
+ p = strappend(path, "/cgroup.procs");
+ if (!p) {
+ errno = ENOMEM;
+ return 1;
+ }
+
+ is_sticky = file_is_priv_sticky(p) > 0;
+ free(p);
+
+ if (is_sticky)
+ return 0;
+
+ /* Compatibility */
p = strappend(path, "/tasks");
if (!p) {
errno = ENOMEM;
bool is_sticky;
char *p;
- p = strappend(fs, "/tasks");
+ p = strappend(fs, "/cgroup.procs");
if (!p)
return -ENOMEM;
is_sticky = file_is_priv_sticky(p) > 0;
free(p);
+ if (!is_sticky) {
+ p = strappend(fs, "/tasks");
+ if (!p)
+ return -ENOMEM;
+
+ is_sticky = file_is_priv_sticky(p) > 0;
+ free(p);
+ }
+
if (!is_sticky)
if (rmdir(fs) < 0 && errno != ENOENT && r == 0)
return -errno;
assert(path);
assert(pid >= 0);
- r = cg_get_path_and_check(controller, path, "tasks", &fs);
+ r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
if (r < 0)
return r;
if (mode != (mode_t) -1)
mode &= 0666;
- r = cg_get_path(controller, path, "tasks", &fs);
+ r = cg_get_path(controller, path, "cgroup.procs", &fs);
if (r < 0)
return r;
if (r < 0)
return r;
- /* Always keep values for "cgroup.procs" in sync with "tasks" */
- r = cg_get_path(controller, path, "cgroup.procs", &procs);
+ /* Compatibility, Always keep values for "tasks" in sync with
+ * "cgroup.procs" */
+ r = cg_get_path(controller, path, "tasks", &procs);
if (r < 0)
return r;
}
int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
- char fs[sizeof("/proc/") - 1 + DECIMAL_STR_MAX(pid_t) + sizeof("/cgroup")];
_cleanup_fclose_ FILE *f = NULL;
char line[LINE_MAX];
+ const char *fs;
size_t cs;
assert(path);
assert(pid >= 0);
- if (controller && !cg_controller_is_valid(controller, true))
- return -EINVAL;
+ if (controller) {
+ if (!cg_controller_is_valid(controller, true))
+ return -EINVAL;
- if (!controller)
+ controller = normalize_controller(controller);
+ } else
controller = SYSTEMD_CGROUP_CONTROLLER;
if (pid == 0)
- pid = getpid();
+ fs = "/proc/self/cgroup";
+ else
+ fs = procfs_file_alloca(pid, "cgroup");
- sprintf(fs, "/proc/%lu/cgroup", (unsigned long) pid);
f = fopen(fs, "re");
if (!f)
return errno == ENOENT ? -ESRCH : -errno;
cs = strlen(controller);
FOREACH_LINE(line, f, return -errno) {
- char *l, *p;
+ char *l, *p, *w, *e;
+ size_t k;
+ char *state;
+ bool found = false;
truncate_nl(line);
continue;
l++;
- if (!strneq(l, controller, cs))
+ e = strchr(l, ':');
+ if (!e)
continue;
- if (l[cs] != ':')
+ *e = 0;
+
+ FOREACH_WORD_SEPARATOR(w, k, l, ",", state) {
+
+ if (k == cs && memcmp(w, controller, cs) == 0) {
+ found = true;
+ break;
+ }
+
+ if (k == 5 + cs &&
+ memcmp(w, "name=", 5) == 0 &&
+ memcmp(w+5, controller, cs) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
continue;
- p = strdup(l + cs + 1);
+ p = strdup(e + 1);
if (!p)
return -ENOMEM;
assert(path);
- r = cg_enumerate_tasks(controller, path, &f);
+ r = cg_enumerate_processes(controller, path, &f);
if (r < 0)
return r == -ENOENT ? 1 : r;
return 0;
}
-int cg_get_machine_path(char **path) {
- _cleanup_free_ char *root = NULL;
+int cg_get_machine_path(const char *machine, char **path) {
+ _cleanup_free_ char *root = NULL, *escaped = NULL;
char *p;
assert(path);
- if (cg_get_root_path(&root) < 0 || streq(root, "/"))
- p = strdup("/machine");
- else
- p = strappend(root, "/machine");
+ if (machine) {
+ const char *name = strappenda(machine, ".nspawn");
+
+ escaped = cg_escape(name);
+ if (!escaped)
+ return -ENOMEM;
+ }
+ p = strjoin(cg_get_root_path(&root) >= 0 && !streq(root, "/") ? root : "",
+ "/machine", machine ? "/" : "", machine ? escaped : "", NULL);
if (!p)
return -ENOMEM;
return cg_path_get_unit(cgroup, unit);
}
-static const char *skip_label(const char *e) {
+_pure_ static const char *skip_label(const char *e) {
assert(e);
e = strchr(e, '/');
/* The return value of this function (unlike cg_unescape())
* needs free()! */
- if (p[0] == '_' || streq(p, "notify_on_release") || streq(p, "release_agent") || streq(p, "tasks"))
+ if (p[0] == 0 ||
+ p[0] == '_' ||
+ p[0] == '.' ||
+ streq(p, "notify_on_release") ||
+ streq(p, "release_agent") ||
+ streq(p, "tasks"))
need_prefix = true;
else {
const char *dot;