]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/cgroup-util.c
util-lib: split string parsing related calls from util.[ch] into parse-util.[ch]
[thirdparty/systemd.git] / src / basic / cgroup-util.c
index 4fcff87dfad509622ff1b8850abeec8c1b6cf674..232d6e8fe24ebfb45e5c90eef537f31b55ce038b 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <dirent.h>
 #include <errno.h>
-#include <unistd.h>
+#include <ftw.h>
 #include <signal.h>
-#include <string.h>
 #include <stdlib.h>
-#include <dirent.h>
+#include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <ftw.h>
+#include <unistd.h>
 
-#include "set.h"
-#include "macro.h"
-#include "util.h"
+#include "cgroup-util.h"
+#include "extract-word.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
-#include "process-util.h"
+#include "login-util.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "parse-util.h"
 #include "path-util.h"
-#include "unit-name.h"
-#include "fileio.h"
+#include "process-util.h"
+#include "set.h"
 #include "special.h"
-#include "mkdir.h"
-#include "login-util.h"
-#include "cgroup-util.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "user-util.h"
+#include "util.h"
 
 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
         _cleanup_free_ char *fs = NULL;
@@ -187,7 +192,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
                         if (ignore_self && pid == my_pid)
                                 continue;
 
-                        if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
+                        if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
                                 continue;
 
                         /* If we haven't killed this process yet, kill
@@ -205,7 +210,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
 
                         done = false;
 
-                        r = set_put(s, LONG_TO_PTR(pid));
+                        r = set_put(s, PID_TO_PTR(pid));
                         if (r < 0) {
                                 if (ret >= 0)
                                         return r;
@@ -318,7 +323,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
                         if (ignore_self && pid == my_pid)
                                 continue;
 
-                        if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
+                        if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
                                 continue;
 
                         /* Ignore kernel threads. Since they can only
@@ -338,7 +343,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
 
                         done = false;
 
-                        r = set_put(s, LONG_TO_PTR(pid));
+                        r = set_put(s, PID_TO_PTR(pid));
                         if (r < 0) {
                                 if (ret >= 0)
                                         return r;
@@ -460,20 +465,23 @@ static const char *controller_to_dirname(const char *controller) {
         return controller;
 }
 
-static int join_path_legacy(const char *controller_dn, const char *path, const char *suffix, char **fs) {
+static int join_path_legacy(const char *controller, const char *path, const char *suffix, char **fs) {
+        const char *dn;
         char *t = NULL;
 
         assert(fs);
-        assert(controller_dn);
+        assert(controller);
+
+        dn = controller_to_dirname(controller);
 
         if (isempty(path) && isempty(suffix))
-                t = strappend("/sys/fs/cgroup/", controller_dn);
+                t = strappend("/sys/fs/cgroup/", dn);
         else if (isempty(path))
-                t = strjoin("/sys/fs/cgroup/", controller_dn, "/", suffix, NULL);
+                t = strjoin("/sys/fs/cgroup/", dn, "/", suffix, NULL);
         else if (isempty(suffix))
-                t = strjoin("/sys/fs/cgroup/", controller_dn, "/", path, NULL);
+                t = strjoin("/sys/fs/cgroup/", dn, "/", path, NULL);
         else
-                t = strjoin("/sys/fs/cgroup/", controller_dn, "/", path, "/", suffix, NULL);
+                t = strjoin("/sys/fs/cgroup/", dn, "/", path, "/", suffix, NULL);
         if (!t)
                 return -ENOMEM;
 
@@ -509,15 +517,15 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
         if (!controller) {
                 char *t;
 
-                /* If no controller is specified, we assume only the
-                 * path below the controller matters */
+                /* If no controller is specified, we return the path
+                 * *below* the controllers, without any prefix. */
 
                 if (!path && !suffix)
                         return -EINVAL;
 
-                if (isempty(suffix))
+                if (!suffix)
                         t = strdup(path);
-                else if (isempty(path))
+                else if (!path)
                         t = strdup(suffix);
                 else
                         t = strjoin(path, "/", suffix, NULL);
@@ -537,17 +545,8 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
 
         if (unified > 0)
                 r = join_path_unified(path, suffix, fs);
-        else {
-                const char *dn;
-
-                if (controller)
-                        dn = controller_to_dirname(controller);
-                else
-                        dn = NULL;
-
-                r = join_path_legacy(dn, path, suffix, fs);
-        }
-
+        else
+                r = join_path_legacy(controller, path, suffix, fs);
         if (r < 0)
                 return r;
 
@@ -876,7 +875,7 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
                 return 0;
         }
 
-        return -ENOENT;
+        return -ENODATA;
 }
 
 int cg_install_release_agent(const char *controller, const char *agent) {
@@ -905,7 +904,7 @@ int cg_install_release_agent(const char *controller, const char *agent) {
                 r = write_string_file(fs, agent, 0);
                 if (r < 0)
                         return r;
-        } else if (!streq(sc, agent))
+        } else if (!path_equal(sc, agent))
                 return -EEXIST;
 
         fs = mfree(fs);
@@ -1008,6 +1007,8 @@ int cg_is_empty_recursive(const char *controller, const char *path) {
                         return r;
 
                 r = read_one_line_file(populated, &t);
+                if (r == -ENOENT)
+                        return 1;
                 if (r < 0)
                         return r;
 
@@ -1901,7 +1902,7 @@ int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids,
         int r = 0;
 
         SET_FOREACH(pidp, pids, i) {
-                pid_t pid = PTR_TO_LONG(pidp);
+                pid_t pid = PTR_TO_PID(pidp);
                 int q;
 
                 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
@@ -1914,7 +1915,7 @@ int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids,
 
 int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
         CGroupController c;
-        int r, unified;
+        int r = 0, unified;
 
         if (!path_equal(from, to))  {
                 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
@@ -1985,14 +1986,22 @@ int cg_mask_supported(CGroupMask *ret) {
         if (unified < 0)
                 return unified;
         if (unified > 0) {
-                _cleanup_free_ char *controllers = NULL;
+                _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
                  * cgroup attribute */
 
-                r = read_one_line_file("/sys/fs/cgroup/cgroup.controllers", &controllers);
+                r = cg_get_root_path(&root);
+                if (r < 0)
+                        return r;
+
+                r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, "cgroup.controllers", &path);
+                if (r < 0)
+                        return r;
+
+                r = read_one_line_file(path, &controllers);
                 if (r < 0)
                         return r;
 
@@ -2014,9 +2023,10 @@ int cg_mask_supported(CGroupMask *ret) {
                         mask |= CGROUP_CONTROLLER_TO_MASK(v);
                 }
 
-                /* Currently, we only support the memory controller in
-                 * the unified hierarchy, mask everything else off. */
-                mask &= CGROUP_MASK_MEMORY;
+                /* Currently, we only support the memory and pids
+                 * controller in the unified hierarchy, mask
+                 * everything else off. */
+                mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_PIDS;
 
         } else {
                 CGroupController c;
@@ -2159,7 +2169,7 @@ int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
 
                         r = write_string_file(fs, s, 0);
                         if (r < 0)
-                                log_warning_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs);
+                                log_debug_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs);
                 }
         }
 
@@ -2202,12 +2212,54 @@ bool cg_is_legacy_wanted(void) {
         return !cg_is_unified_wanted();
 }
 
+int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
+        uint64_t u;
+        int r;
+
+        if (isempty(s)) {
+                *ret = CGROUP_CPU_SHARES_INVALID;
+                return 0;
+        }
+
+        r = safe_atou64(s, &u);
+        if (r < 0)
+                return r;
+
+        if (u < CGROUP_CPU_SHARES_MIN || u > CGROUP_CPU_SHARES_MAX)
+                return -ERANGE;
+
+        *ret = u;
+        return 0;
+}
+
+int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
+        uint64_t u;
+        int r;
+
+        if (isempty(s)) {
+                *ret = CGROUP_BLKIO_WEIGHT_INVALID;
+                return 0;
+        }
+
+        r = safe_atou64(s, &u);
+        if (r < 0)
+                return r;
+
+        if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX)
+                return -ERANGE;
+
+        *ret = u;
+        return 0;
+}
+
 static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
         [CGROUP_CONTROLLER_CPU] = "cpu",
         [CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
         [CGROUP_CONTROLLER_BLKIO] = "blkio",
         [CGROUP_CONTROLLER_MEMORY] = "memory",
-        [CGROUP_CONTROLLER_DEVICE] = "device",
+        [CGROUP_CONTROLLER_DEVICES] = "devices",
+        [CGROUP_CONTROLLER_PIDS] = "pids",
+        [CGROUP_CONTROLLER_NET_CLS] = "net_cls",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController);