#include "unit-name.h"
#include "fileio.h"
#include "special.h"
+#include "mkdir.h"
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
_cleanup_free_ char *fs = NULL;
return ret;
}
-int cg_kill_recursive_and_wait(const char *controller, const char *path, bool rem) {
- unsigned i;
-
- assert(path);
-
- /* This safely kills all processes; first it sends a SIGTERM,
- * then checks 8 times after 200ms whether the group is now
- * empty, then kills everything that is left with SIGKILL and
- * finally checks 5 times after 200ms each whether the group
- * is finally empty. */
-
- for (i = 0; i < 15; i++) {
- int sig, r;
-
- if (i <= 0)
- sig = SIGTERM;
- else if (i == 9)
- sig = SIGKILL;
- else
- sig = 0;
-
- r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL);
- if (r <= 0)
- return r;
-
- usleep(200 * USEC_PER_MSEC);
- }
-
- return 0;
-}
-
int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) {
bool done = false;
_cleanup_set_free_ Set *s = NULL;
return ret;
}
+int cg_migrate_recursive_fallback(
+ const char *cfrom,
+ const char *pfrom,
+ const char *cto,
+ const char *pto,
+ bool ignore_self,
+ bool rem) {
+
+ int r;
+
+ assert(cfrom);
+ assert(pfrom);
+ assert(cto);
+ assert(pto);
+
+ r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem);
+ if (r < 0) {
+ char prefix[strlen(pto) + 1];
+
+ /* This didn't work? Then let's try all prefixes of the destination */
+
+ PATH_FOREACH_PREFIX(prefix, pto) {
+ r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
+ if (r >= 0)
+ break;
+ }
+ }
+
+ return 0;
+}
+
static const char *normalize_controller(const char *controller) {
assert(controller);
return r == -ENOENT ? 0 : r;
}
+int cg_create(const char *controller, const char *path) {
+ _cleanup_free_ char *fs = NULL;
+ int r;
+
+ r = cg_get_path_and_check(controller, path, NULL, &fs);
+ if (r < 0)
+ return r;
+
+ r = mkdir_parents(fs, 0755);
+ if (r < 0)
+ return r;
+
+ if (mkdir(fs, 0755) < 0) {
+
+ if (errno == EEXIST)
+ return 0;
+
+ return -errno;
+ }
+
+ return 1;
+}
+
+int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
+ int r, q;
+
+ assert(pid >= 0);
+
+ r = cg_create(controller, path);
+ if (r < 0)
+ return r;
+
+ q = cg_attach(controller, path, pid);
+ if (q < 0)
+ return q;
+
+ /* This does not remove the cgroup on failure */
+ return r;
+}
+
int cg_attach(const char *controller, const char *path, pid_t pid) {
_cleanup_free_ char *fs = NULL;
char c[DECIMAL_STR_MAX(pid_t) + 2];
return write_string_file(fs, c);
}
+int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
+ int r;
+
+ assert(controller);
+ assert(path);
+ assert(pid >= 0);
+
+ r = cg_attach(controller, path, pid);
+ if (r < 0) {
+ char prefix[strlen(path) + 1];
+
+ /* This didn't work? Then let's try all prefixes of
+ * the destination */
+
+ PATH_FOREACH_PREFIX(prefix, path) {
+ r = cg_attach(controller, prefix, pid);
+ if (r >= 0)
+ break;
+ }
+ }
+
+ return 0;
+}
+
int cg_set_group_access(
const char *controller,
const char *path,
return 0;
}
+int cg_uninstall_release_agent(const char *controller) {
+ _cleanup_free_ char *fs = NULL;
+ int r;
+
+ r = cg_get_path(controller, NULL, "notify_on_release", &fs);
+ if (r < 0)
+ return r;
+
+ r = write_string_file(fs, "0");
+ if (r < 0)
+ return r;
+
+ free(fs);
+ fs = NULL;
+
+ r = cg_get_path(controller, NULL, "release_agent", &fs);
+ if (r < 0)
+ return r;
+
+ r = write_string_file(fs, "");
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
_cleanup_fclose_ FILE *f = NULL;
pid_t pid = 0, self_pid;
return !found;
}
-int cg_is_empty_by_spec(const char *spec, bool ignore_self) {
- _cleanup_free_ char *controller = NULL, *path = NULL;
- int r;
-
- assert(spec);
-
- r = cg_split_spec(spec, &controller, &path);
- if (r < 0)
- return r;
-
- return cg_is_empty(controller, path, ignore_self);
-}
-
int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
_cleanup_closedir_ DIR *d = NULL;
char *fn;
return -EINVAL;
}
- u = strdup(e+1);
- if (!u) {
- free(t);
- return -ENOMEM;
- }
- if (!path_is_safe(u) ||
- !path_is_absolute(u)) {
- free(t);
- free(u);
- return -EINVAL;
- }
+ if (streq(e+1, "")) {
+ u = strdup("/");
+ if (!u) {
+ free(t);
+ return -ENOMEM;
+ }
+ } else {
+ u = strdup(e+1);
+ if (!u) {
+ free(t);
+ return -ENOMEM;
+ }
- path_kill_slashes(u);
+ if (!path_is_safe(u) ||
+ !path_is_absolute(u)) {
+ free(t);
+ free(u);
+ return -EINVAL;
+ }
+
+ path_kill_slashes(u);
+ }
if (controller)
*controller = t;
return 0;
}
-int cg_join_spec(const char *controller, const char *path, char **spec) {
- char *s;
-
- assert(path);
-
- if (!controller)
- controller = "systemd";
- else {
- if (!cg_controller_is_valid(controller, true))
- return -EINVAL;
-
- controller = normalize_controller(controller);
- }
-
- if (!path_is_absolute(path))
- return -EINVAL;
-
- s = strjoin(controller, ":", path, NULL);
- if (!s)
- return -ENOMEM;
-
- path_kill_slashes(s + strlen(controller) + 1);
-
- *spec = s;
- return 0;
-}
-
int cg_mangle_path(const char *path, char **result) {
_cleanup_free_ char *c = NULL, *p = NULL;
char *t;
return 0;
}
-char **cg_shorten_controllers(char **controllers) {
- char **f, **t;
-
- if (!controllers)
- return controllers;
-
- for (f = controllers, t = controllers; *f; f++) {
- const char *p;
- int r;
-
- p = normalize_controller(*f);
-
- if (streq(p, "systemd")) {
- free(*f);
- continue;
- }
-
- if (!cg_controller_is_valid(p, true)) {
- log_warning("Controller %s is not valid, removing from controllers list.", p);
- free(*f);
- continue;
- }
-
- r = check_hierarchy(p);
- if (r < 0) {
- log_debug("Controller %s is not available, removing from controllers list.", p);
- free(*f);
- continue;
- }
-
- *(t++) = *f;
- }
-
- *t = NULL;
- return strv_uniq(controllers);
-}
-
int cg_pid_get_path_shifted(pid_t pid, char **root, char **cgroup) {
_cleanup_free_ char *cg_root = NULL;
char *cg_process, *p;
}
int cg_path_decode_unit(const char *cgroup, char **unit){
- char *p, *e, *c, *s, *k;
+ char *e, *c, *s;
assert(cgroup);
assert(unit);
c = strndupa(cgroup, e - cgroup);
c = cg_unescape(c);
- /* Could this be a valid unit name? */
- if (!unit_name_is_valid(c, true))
+ if (!unit_name_is_valid(c, false))
return -EINVAL;
- if (!unit_name_is_template(c))
- s = strdup(c);
- else {
- if (*e != '/')
- return -EINVAL;
-
- e += strspn(e, "/");
-
- p = strchrnul(e, '/');
- k = strndupa(e, p - e);
- k = cg_unescape(k);
-
- if (!unit_name_is_valid(k, false))
- return -EINVAL;
-
- s = strdup(k);
- }
-
+ s = strdup(c);
if (!s)
return -ENOMEM;
return cg_path_get_unit(cgroup, unit);
}
-static const char *skip_user(const char *p) {
- size_t n;
-
- assert(p);
-
- p += strspn(p, "/");
-
- n = strcspn(p, "/");
- if (n <= 5 || memcmp(p + n - 5, ".user", 5) != 0)
- return p;
-
- p += n;
- p += strspn(p, "/");
-
- return p;
-}
-
static const char *skip_session(const char *p) {
size_t n;
p += strspn(p, "/");
n = strcspn(p, "/");
- if (n <= 8 || memcmp(p + n - 8, ".session", 8) != 0)
+ if (n <= 12 || memcmp(p, "session-", 8) != 0 || memcmp(p + n - 6, ".scope", 6) != 0)
return NULL;
p += n;
return p;
}
-static const char *skip_systemd_label(const char *p) {
- size_t n;
-
- assert(p);
-
- p += strspn(p, "/");
-
- n = strcspn(p, "/");
- if (n < 8 || memcmp(p, "systemd-", 8) != 0)
- return p;
-
- p += n;
- p += strspn(p, "/");
-
- return p;
-}
-
int cg_path_get_user_unit(const char *path, char **unit) {
const char *e;
/* Skip slices, if there are any */
e = skip_slices(path);
- /* Skip the user name, if there is one */
- e = skip_user(e);
-
- /* Skip the session ID, require that there is one */
+ /* Skip the session scope, require that there is one */
e = skip_session(e);
if (!e)
return -ENOENT;
- /* Skip the systemd cgroup, if there is one */
- e = skip_systemd_label(e);
+ /* And skip more slices */
+ e = skip_slices(e);
return cg_path_decode_unit(e, unit);
}
int cg_path_get_machine_name(const char *path, char **machine) {
const char *e, *n, *x;
char *s, *r;
+ size_t l;
assert(path);
assert(machine);
s = strndupa(e, n - e);
s = cg_unescape(s);
- x = endswith(s, ".machine");
+ x = startswith(s, "machine-");
if (!x)
return -ENOENT;
+ if (!endswith(x, ".scope"))
+ return -ENOENT;
- r = strndup(s, x - s);
+ l = strlen(x);
+ if (l <= 6)
+ return -ENOENT;
+
+ r = strndup(x, l - 6);
if (!r)
return -ENOMEM;
}
int cg_path_get_session(const char *path, char **session) {
- const char *e, *n;
- char *s;
+ const char *e, *n, *x;
+ char *s, *r;
+ size_t l;
assert(path);
assert(session);
/* Skip slices, if there are any */
e = skip_slices(path);
- /* Skip the user name, if there is one */
- e = skip_user(e);
-
n = strchrnul(e, '/');
- if (n - e < 8)
+ if (e == n)
+ return -ENOENT;
+
+ s = strndupa(e, n - e);
+ s = cg_unescape(s);
+
+ x = startswith(s, "session-");
+ if (!x)
return -ENOENT;
- if (memcmp(n - 8, ".session", 8) != 0)
+ if (!endswith(x, ".scope"))
return -ENOENT;
- s = strndup(e, n - e - 8);
- if (!s)
+ l = strlen(x);
+ if (l <= 6)
+ return -ENOENT;
+
+ r = strndup(x, l - 6);
+ if (!r)
return -ENOMEM;
- *session = s;
+ *session = r;
return 0;
}
}
int cg_path_get_owner_uid(const char *path, uid_t *uid) {
- const char *e, *n;
+ _cleanup_free_ char *slice = NULL;
+ const char *start, *end;
char *s;
+ uid_t u;
+ int r;
assert(path);
- assert(uid);
- /* Skip slices, if there are any */
- e = skip_slices(path);
+ r = cg_path_get_slice(path, &slice);
+ if (r < 0)
+ return r;
- n = strchrnul(e, '/');
- if (n - e < 5)
+ start = startswith(slice, "user-");
+ if (!start)
return -ENOENT;
- if (memcmp(n - 5, ".user", 5) != 0)
+ end = endswith(slice, ".slice");
+ if (!end)
return -ENOENT;
- s = strndupa(e, n - e - 5);
+ s = strndupa(start, end - start);
if (!s)
- return -ENOMEM;
+ return -ENOENT;
+
+ if (parse_uid(s, &u) < 0)
+ return -EIO;
- return parse_uid(s, uid);
+ if (uid)
+ *uid = u;
+
+ return 0;
}
int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
_cleanup_free_ char *cgroup = NULL;
int r;
- assert(uid);
-
r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
if (r < 0)
return r;
return cg_path_get_slice(cgroup, slice);
}
-int cg_controller_from_attr(const char *attr, char **controller) {
- const char *dot;
- char *c;
-
- assert(attr);
- assert(controller);
-
- if (!filename_is_safe(attr))
- return -EINVAL;
-
- dot = strchr(attr, '.');
- if (!dot) {
- *controller = NULL;
- return 0;
- }
-
- c = strndup(attr, dot - attr);
- if (!c)
- return -ENOMEM;
-
- if (!cg_controller_is_valid(c, false)) {
- free(c);
- return -EINVAL;
- }
-
- *controller = c;
- return 1;
-}
-
char *cg_escape(const char *p) {
bool need_prefix = false;
}
#define CONTROLLER_VALID \
- "0123456789" \
- "abcdefghijklmnopqrstuvwxyz" \
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+ DIGITS LETTERS \
"_"
bool cg_controller_is_valid(const char *p, bool allow_named) {
"memory\0"
"devices\0";
-int cg_create_with_mask(CGroupControllerMask mask, const char *path) {
+int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
CGroupControllerMask bit = 1;
const char *n;
int r;
/* Then, do the same in the other hierarchies */
NULSTR_FOREACH(n, mask_names) {
- if (bit & mask)
+ if (mask & bit)
cg_create(n, path);
- else
+ else if (supported & bit)
cg_trim(n, path, true);
bit <<= 1;
}
- return r;
+ return 0;
}
-int cg_attach_with_mask(CGroupControllerMask mask, const char *path, pid_t pid) {
+int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid) {
CGroupControllerMask bit = 1;
const char *n;
int r;
r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
+ if (r < 0)
+ return r;
NULSTR_FOREACH(n, mask_names) {
- if (bit & mask)
- cg_attach(n, path, pid);
- else {
- char prefix[strlen(path) + 1], *slash;
-
- /* OK, this one is a bit harder... Now we need
- * to add to the closest parent cgroup we
- * can find */
- strcpy(prefix, path);
- while ((slash = strrchr(prefix, '/'))) {
- int q;
- *slash = 0;
-
- q = cg_attach(n, prefix, pid);
- if (q >= 0)
- break;
- }
- }
+ if (supported & bit)
+ cg_attach_fallback(n, path, pid);
bit <<= 1;
}
- return r;
+ return 0;
}
-int cg_attach_many_with_mask(CGroupControllerMask mask, const char *path, Set* pids) {
+int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids) {
Iterator i;
void *pidp;
int r = 0;
SET_FOREACH(pidp, pids, i) {
pid_t pid = PTR_TO_LONG(pidp);
- int k;
+ int q;
- k = cg_attach_with_mask(mask, path, pid);
- if (k < 0)
- r = k;
+ q = cg_attach_everywhere(supported, path, pid);
+ if (q < 0)
+ r = q;
}
return r;
}
-int cg_migrate_with_mask(CGroupControllerMask mask, const char *from, const char *to) {
+int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to) {
CGroupControllerMask bit = 1;
const char *n;
int r;
- if (path_equal(from, to))
- return 0;
-
- r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
+ if (!path_equal(from, to)) {
+ r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
+ if (r < 0)
+ return r;
+ }
NULSTR_FOREACH(n, mask_names) {
- if (bit & mask)
- cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, to, n, to, false, false);
- else {
- char prefix[strlen(to) + 1], *slash;
-
- strcpy(prefix, to);
- while ((slash = strrchr(prefix, '/'))) {
- int q;
-
- *slash = 0;
-
- q = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, to, n, prefix, false, false);
- if (q >= 0)
- break;
- }
- }
+ if (supported & bit)
+ cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, n, to, false, false);
bit <<= 1;
}
- return r;
+ return 0;
}
-int cg_trim_with_mask(CGroupControllerMask mask, const char *path, bool delete_root) {
+int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
CGroupControllerMask bit = 1;
const char *n;
int r;
return r;
NULSTR_FOREACH(n, mask_names) {
- if (bit & mask)
+ if (supported & bit)
cg_trim(n, path, delete_root);
bit <<= 1;
}
- return r;
+ return 0;
}
CGroupControllerMask cg_mask_supported(void) {