chiark / gitweb /
cgroup: if we do a cgroup operation then do something on all supported controllers
[elogind.git] / src / shared / cgroup-util.c
index 5816b7d4d6fd991a3c4d9cb8ce17ba978a8ab502..2e630d4708d6f14814762794d2fe21345322016e 100644 (file)
@@ -435,6 +435,46 @@ int cg_migrate_recursive(
         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 */
+
+                strcpy(prefix, pto);
+                for (;;) {
+                        char *slash;
+
+                        slash = strrchr(prefix, '/');
+                        if (!slash)
+                                break;
+
+                        *slash = 0;
+
+                        r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
+                        if (r >= 0)
+                                break;
+                }
+        }
+
+        return r;
+}
+
 static const char *normalize_controller(const char *controller) {
 
         assert(controller);
@@ -607,6 +647,39 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
         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 */
+
+                strcpy(prefix, path);
+                for (;;) {
+                        char *slash;
+
+                        slash = strrchr(prefix, '/');
+                        if (!slash)
+                                break;
+
+                        *slash = 0;
+
+                        r = cg_attach(controller, prefix, pid);
+                        if (r >= 0)
+                                break;
+                }
+        }
+
+        return r;
+}
+
 int cg_set_group_access(
                 const char *controller,
                 const char *path,
@@ -790,6 +863,32 @@ int cg_install_release_agent(const char *controller, const char *agent) {
         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;
@@ -1100,7 +1199,7 @@ int cg_pid_get_path_shifted(pid_t pid, char **root, char **cgroup) {
 }
 
 int cg_path_decode_unit(const char *cgroup, char **unit){
-        char *p, *e, *c, *s, *k;
+        char *e, *c, *s;
 
         assert(cgroup);
         assert(unit);
@@ -1109,28 +1208,10 @@ int cg_path_decode_unit(const char *cgroup, char **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;
 
@@ -1178,23 +1259,6 @@ int cg_pid_get_unit(pid_t pid, char **unit) {
         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;
 
@@ -1203,7 +1267,7 @@ static const char *skip_session(const char *p) {
         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;
@@ -1212,23 +1276,6 @@ static const char *skip_session(const char *p) {
         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;
 
@@ -1242,16 +1289,13 @@ int cg_path_get_user_unit(const char *path, char **unit) {
         /* 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);
 }
@@ -1272,6 +1316,7 @@ int cg_pid_get_user_unit(pid_t pid, char **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);
@@ -1286,11 +1331,17 @@ int cg_path_get_machine_name(const char *path, char **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;
 
@@ -1312,8 +1363,9 @@ int cg_pid_get_machine_name(pid_t pid, char **machine) {
 }
 
 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);
@@ -1321,20 +1373,28 @@ int cg_path_get_session(const char *path, char **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;
 }
 
@@ -1352,22 +1412,25 @@ int cg_pid_get_session(pid_t pid, char **session) {
 }
 
 int cg_path_get_owner_uid(const char *path, uid_t *uid) {
-        const char *e, *n;
+        _cleanup_free_ char *slice = NULL;
+        const char *e;
         char *s;
+        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)
+        e = startswith(slice, "user-");
+        if (!e)
                 return -ENOENT;
-        if (memcmp(n - 5, ".user", 5) != 0)
+        if (!endswith(slice, ".slice"))
                 return -ENOENT;
 
-        s = strndupa(e, n - e - 5);
+        s = strndupa(e, strlen(e) - 6);
         if (!s)
                 return -ENOMEM;
 
@@ -1521,9 +1584,7 @@ char *cg_unescape(const char *p) {
 }
 
 #define CONTROLLER_VALID                        \
-        "0123456789"                            \
-        "abcdefghijklmnopqrstuvwxyz"            \
-        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
+        DIGITS LETTERS                          \
         "_"
 
 bool cg_controller_is_valid(const char *p, bool allow_named) {
@@ -1619,7 +1680,7 @@ static const char mask_names[] =
         "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;
@@ -1635,85 +1696,75 @@ int cg_create_with_mask(CGroupControllerMask mask, const char *path) {
 
         /* 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 0;
+}
+
+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 q;
+
+                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;
@@ -1723,13 +1774,13 @@ int cg_trim_with_mask(CGroupControllerMask mask, const char *path, bool delete_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) {