chiark / gitweb /
cgtop: missing '-'
[elogind.git] / src / cgtop / cgtop.c
index 1fe247c667afae1f5b0a7687411af5d771a8fa19..9eb2d2fdebd108080ba9caaf2ecabb1acfed7880 100644 (file)
 #include <alloca.h>
 #include <getopt.h>
 
+#include "path-util.h"
 #include "util.h"
 #include "hashmap.h"
 #include "cgroup-util.h"
+#include "build.h"
 
 typedef struct Group {
         char *path;
@@ -53,7 +55,9 @@ typedef struct Group {
         uint64_t io_input_bps, io_output_bps;
 } Group;
 
-static unsigned arg_depth = 2;
+static unsigned arg_depth = 3;
+static unsigned arg_iterations = 0;
+static bool arg_batch = false;
 static usec_t arg_delay = 1*USEC_PER_SEC;
 
 static enum {
@@ -296,7 +300,7 @@ static int refresh_one(
 
         r = cg_enumerate_subgroups(controller, path, &d);
         if (r < 0) {
-                if (r == ENOENT)
+                if (r == -ENOENT)
                         return 0;
 
                 return r;
@@ -309,7 +313,7 @@ static int refresh_one(
                 if (r <= 0)
                         goto finish;
 
-                p = join(path, "/", fn, NULL);
+                p = strjoin(path, "/", fn, NULL);
                 free(fn);
 
                 if (!p) {
@@ -340,17 +344,22 @@ static int refresh(Hashmap *a, Hashmap *b, unsigned iteration) {
 
         r = refresh_one("name=systemd", "/", a, b, iteration, 0);
         if (r < 0)
-                return r;
-
+                if (r != -ENOENT)
+                    return r;
         r = refresh_one("cpuacct", "/", a, b, iteration, 0);
         if (r < 0)
-                return r;
-
+                if (r != -ENOENT)
+                    return r;
         r = refresh_one("memory", "/", a, b, iteration, 0);
         if (r < 0)
-                return r;
+                if (r != -ENOENT)
+                    return r;
 
-        return refresh_one("blkio", "/", a, b, iteration, 0);
+        r = refresh_one("blkio", "/", a, b, iteration, 0);
+        if (r < 0)
+                if (r != -ENOENT)
+                    return r;
+        return 0;
 }
 
 static int group_compare(const void*a, const void *b) {
@@ -418,7 +427,7 @@ static int display(Hashmap *a) {
         Iterator i;
         Group *g;
         Group **array;
-        unsigned rows, n = 0, j;
+        unsigned rows, path_columns, n = 0, j;
 
         assert(a);
 
@@ -438,13 +447,23 @@ static int display(Hashmap *a) {
         if (rows <= 0)
                 rows = 25;
 
-        printf("%s%-37s%s %s%7s%s %s%6s%s %s%8s%s %s%8s%s %s%8s%s\n\n",
-               arg_order == ORDER_PATH   ? ANSI_HIGHLIGHT_ON : "", "Path",     arg_order == ORDER_PATH   ? ANSI_HIGHLIGHT_OFF : "",
-               arg_order == ORDER_TASKS  ? ANSI_HIGHLIGHT_ON : "", "Tasks",    arg_order == ORDER_TASKS  ? ANSI_HIGHLIGHT_OFF : "",
-               arg_order == ORDER_CPU    ? ANSI_HIGHLIGHT_ON : "", "%CPU",     arg_order == ORDER_CPU    ? ANSI_HIGHLIGHT_OFF : "",
-               arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_ON : "", "Memory",   arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_OFF : "",
-               arg_order == ORDER_IO     ? ANSI_HIGHLIGHT_ON : "", "Input/s",  arg_order == ORDER_IO     ? ANSI_HIGHLIGHT_OFF : "",
-               arg_order == ORDER_IO     ? ANSI_HIGHLIGHT_ON : "", "Output/s", arg_order == ORDER_IO     ? ANSI_HIGHLIGHT_OFF : "");
+        path_columns = columns_uncached() - 42;
+        if (path_columns < 10)
+                path_columns = 10;
+
+        printf("%s%-*s%s %s%7s%s %s%6s%s %s%8s%s %s%8s%s %s%8s%s\n\n",
+               arg_order == ORDER_PATH   ? ANSI_HIGHLIGHT_ON : "", path_columns, "Path",
+                      arg_order == ORDER_PATH   ? ANSI_HIGHLIGHT_OFF : "",
+               arg_order == ORDER_TASKS  ? ANSI_HIGHLIGHT_ON : "", "Tasks",
+                      arg_order == ORDER_TASKS  ? ANSI_HIGHLIGHT_OFF : "",
+               arg_order == ORDER_CPU    ? ANSI_HIGHLIGHT_ON : "", "%CPU",
+                      arg_order == ORDER_CPU    ? ANSI_HIGHLIGHT_OFF : "",
+               arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_ON : "", "Memory",
+                      arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_OFF : "",
+               arg_order == ORDER_IO     ? ANSI_HIGHLIGHT_ON : "", "Input/s",
+                      arg_order == ORDER_IO     ? ANSI_HIGHLIGHT_OFF : "",
+               arg_order == ORDER_IO     ? ANSI_HIGHLIGHT_ON : "", "Output/s",
+                      arg_order == ORDER_IO     ? ANSI_HIGHLIGHT_OFF : "");
 
         for (j = 0; j < n; j++) {
                 char *p;
@@ -455,8 +474,8 @@ static int display(Hashmap *a) {
 
                 g = array[j];
 
-                p = ellipsize(g->path, 37, 33);
-                printf("%-37s", p ? p : g->path);
+                p = ellipsize(g->path, path_columns, 33);
+                printf("%-*s", path_columns, p ? p : g->path);
                 free(p);
 
                 if (g->n_tasks_valid)
@@ -493,27 +512,38 @@ static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Show top control groups by their resource usage.\n\n"
                "  -h --help           Show this help\n"
+               "  --version           Print version and exit\n"
                "  -p                  Order by path\n"
                "  -t                  Order by number of tasks\n"
                "  -c                  Order by CPU load\n"
                "  -m                  Order by memory load\n"
                "  -i                  Order by IO load\n"
                "  -d --delay=DELAY    Specify delay\n"
+               "  -n --iterations=N   Run for N iterations before exiting\n"
+               "  -b --batch          Run in batch mode, accepting no input\n"
                "     --depth=DEPTH    Maximum traversal depth (default: 2)\n",
                program_invocation_short_name);
 }
 
+static void version(void) {
+        puts(PACKAGE_STRING " cgtop");
+}
+
 static int parse_argv(int argc, char *argv[]) {
 
         enum {
-                ARG_DEPTH = 0x100
+                ARG_VERSION = 0x100,
+                ARG_DEPTH,
         };
 
         static const struct option options[] = {
-                { "help",  no_argument,       NULL, 'h'       },
-                { "delay", required_argument, NULL, 'd'       },
-                { "depth", required_argument, NULL, ARG_DEPTH },
-                { NULL,    0,                 NULL, 0         }
+                { "help",       no_argument,       NULL, 'h'         },
+                { "version",    no_argument,       NULL, ARG_VERSION },
+                { "delay",      required_argument, NULL, 'd'         },
+                { "iterations", required_argument, NULL, 'n'         },
+                { "batch",      no_argument,       NULL, 'b'         },
+                { "depth",      required_argument, NULL, ARG_DEPTH   },
+                { NULL,         0,                 NULL, 0           }
         };
 
         int c;
@@ -522,7 +552,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 1);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hptcmid:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hptcmin:bd:", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -530,6 +560,10 @@ static int parse_argv(int argc, char *argv[]) {
                         help();
                         return 0;
 
+                case ARG_VERSION:
+                        version();
+                        return 0;
+
                 case ARG_DEPTH:
                         r = safe_atou(optarg, &arg_depth);
                         if (r < 0) {
@@ -548,6 +582,19 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case 'n':
+                        r = safe_atou(optarg, &arg_iterations);
+                        if (r < 0) {
+                                log_error("Failed to parse iterations parameter.");
+                                return -EINVAL;
+                        }
+
+                        break;
+
+                case 'b':
+                        arg_batch = true;
+                        break;
+
                 case 'p':
                         arg_order = ORDER_PATH;
                         break;
@@ -602,8 +649,7 @@ int main(int argc, char *argv[]) {
         a = hashmap_new(string_hash_func, string_compare_func);
         b = hashmap_new(string_hash_func, string_compare_func);
         if (!a || !b) {
-                log_error("Out of memory");
-                r = -ENOMEM;
+                r = log_oom();
                 goto finish;
         }
 
@@ -635,17 +681,28 @@ int main(int argc, char *argv[]) {
                 if (r < 0)
                         goto finish;
 
-                r = read_one_char(stdin, &key, last_refresh + arg_delay - t, NULL);
-                if (r == -ETIMEDOUT)
-                        continue;
-                if (r < 0) {
-                        log_error("Couldn't read key: %s", strerror(-r));
-                        goto finish;
+                if (arg_iterations && iteration >= arg_iterations)
+                        break;
+
+                if (arg_batch) {
+                        usleep(last_refresh + arg_delay - t);
+                } else {
+                        r = read_one_char(stdin, &key,
+                                          last_refresh + arg_delay - t, NULL);
+                        if (r == -ETIMEDOUT)
+                                continue;
+                        if (r < 0) {
+                                log_error("Couldn't read key: %s", strerror(-r));
+                                goto finish;
+                        }
                 }
 
                 fputs("\r \r", stdout);
                 fflush(stdout);
 
+                if (arg_batch)
+                        continue;
+
                 switch (key) {
 
                 case ' ':
@@ -725,5 +782,10 @@ finish:
         group_hashmap_free(a);
         group_hashmap_free(b);
 
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+        if (r < 0) {
+                log_error("Exiting with failure: %s", strerror(-r));
+                return EXIT_FAILURE;
+        }
+
+        return EXIT_SUCCESS;
 }