]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/cgtop/cgtop.c
tree-wide: drop license boilerplate
[thirdparty/systemd.git] / src / cgtop / cgtop.c
index 4e406e4ad252b5e7efd6365be7814a7265b42021..7fe812d0ffd83b9f79397b5d6faebda8eff2453a 100644 (file)
@@ -3,19 +3,6 @@
   This file is part of systemd.
 
   Copyright 2012 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
 #include <alloca.h>
@@ -46,6 +33,7 @@
 #include "terminal-util.h"
 #include "unit-name.h"
 #include "util.h"
+#include "virt.h"
 
 typedef struct Group {
         char *path;
@@ -126,6 +114,26 @@ static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, uint64
 }
 
 static bool is_root_cgroup(const char *path) {
+
+        /* Returns true if the specified path belongs to the root cgroup. The root cgroup is special on cgroupsv2 as it
+         * carries only very few attributes in order not to export multiple truth about system state as most
+         * information is available elsewhere in /proc anyway. We need to be able to deal with that, and need to get
+         * our data from different sources in that case.
+         *
+         * There's one extra complication in all of this, though ðŸ˜£: if the path to the cgroup indicates we are in the
+         * root cgroup this might actually not be the case, because cgroup namespacing might be in effect
+         * (CLONE_NEWCGROUP). Since there's no nice way to distuingish a real cgroup root from a fake namespaced one we
+         * do an explicit container check here, under the assumption that CLONE_NEWCGROUP is generally used when
+         * container managers are used too.
+         *
+         * Note that checking for a container environment is kinda ugly, since in theory people could use cgtop from
+         * inside a container where cgroup namespacing is turned off to watch the host system. However, that's mostly a
+         * theoretic usecase, and if people actually try all they'll lose is accounting for the top-level cgroup. Which
+         * isn't too bad. */
+
+        if (detect_container() > 0)
+                return false;
+
         return isempty(path) || path_equal(path, "/");
 }
 
@@ -176,7 +184,8 @@ static int process(
                 }
         }
 
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES)) {
+        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) &&
+            IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES)) {
                 _cleanup_fclose_ FILE *f = NULL;
                 pid_t pid;
 
@@ -230,15 +239,18 @@ static int process(
                 uint64_t new_usage;
                 nsec_t timestamp;
 
-                if (all_unified) {
-                        const char *keys[] = { "usage_usec", NULL };
+                if (is_root_cgroup(path)) {
+                        r = procfs_cpu_get_usage(&new_usage);
+                        if (r < 0)
+                                return r;
+                } else if (all_unified) {
                         _cleanup_free_ char *val = NULL;
 
                         if (!streq(controller, "cpu"))
                                 return 0;
 
-                        r = cg_get_keyed_attribute("cpu", path, "cpu.stat", keys, &val);
-                        if (r == -ENOENT)
+                        r = cg_get_keyed_attribute("cpu", path, "cpu.stat", STRV_MAKE("usage_usec"), &val);
+                        if (IN_SET(r, -ENOENT, -ENXIO))
                                 return 0;
                         if (r < 0)
                                 return r;
@@ -288,24 +300,31 @@ static int process(
                 g->cpu_iteration = iteration;
 
         } else if (streq(controller, "memory")) {
-                _cleanup_free_ char *p = NULL, *v = NULL;
 
-                if (all_unified)
-                        r = cg_get_path(controller, path, "memory.current", &p);
-                else
-                        r = cg_get_path(controller, path, "memory.usage_in_bytes", &p);
-                if (r < 0)
-                        return r;
+                if (is_root_cgroup(path)) {
+                        r = procfs_memory_get_current(&g->memory);
+                        if (r < 0)
+                                return r;
+                } else {
+                        _cleanup_free_ char *p = NULL, *v = NULL;
 
-                r = read_one_line_file(p, &v);
-                if (r == -ENOENT)
-                        return 0;
-                if (r < 0)
-                        return r;
+                        if (all_unified)
+                                r = cg_get_path(controller, path, "memory.current", &p);
+                        else
+                                r = cg_get_path(controller, path, "memory.usage_in_bytes", &p);
+                        if (r < 0)
+                                return r;
 
-                r = safe_atou64(v, &g->memory);
-                if (r < 0)
-                        return r;
+                        r = read_one_line_file(p, &v);
+                        if (r == -ENOENT)
+                                return 0;
+                        if (r < 0)
+                                return r;
+
+                        r = safe_atou64(v, &g->memory);
+                        if (r < 0)
+                                return r;
+                }
 
                 if (g->memory > 0)
                         g->memory_valid = true;
@@ -935,8 +954,8 @@ int main(int argc, char *argv[]) {
         } else
                 log_debug("Cgroup path: %s", root);
 
-        a = hashmap_new(&string_hash_ops);
-        b = hashmap_new(&string_hash_ops);
+        a = hashmap_new(&path_hash_ops);
+        b = hashmap_new(&path_hash_ops);
         if (!a || !b) {
                 r = log_oom();
                 goto finish;