/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#include <getopt.h>
#include <signal.h>
#include <unistd.h>
#include "cgroup-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "format-table.h"
#include "hashmap.h"
#include "log.h"
#include "main-func.h"
+#include "options.h"
#include "parse-argument.h"
#include "parse-util.h"
#include "path-util.h"
_CPU_INVALID = -EINVAL,
} CPUType;
-static unsigned arg_depth = 3;
+#define DEFAULT_MAXIMUM_DEPTH 3
+
+static unsigned arg_depth = DEFAULT_MAXIMUM_DEPTH;
static unsigned arg_iterations = UINT_MAX;
static bool arg_batch = false;
static bool arg_raw = false;
static usec_t arg_delay = 1*USEC_PER_SEC;
-static char* arg_machine = NULL;
-static char* arg_root = NULL;
+static const char *arg_machine = NULL;
+static const char *arg_root = NULL;
static bool arg_recursive = true;
static bool arg_recursive_unset = false;
static PidsCount arg_count = COUNT_PIDS;
static int help(void) {
_cleanup_free_ char *link = NULL;
+ _cleanup_(table_unrefp) Table *options = NULL;
int r;
r = terminal_urlify_man("systemd-cgtop", "1", &link);
if (r < 0)
return log_oom();
+ r = option_parser_get_help_table(&options);
+ if (r < 0)
+ return r;
+
printf("%s [OPTIONS...] [CGROUP]\n\n"
- "Show top control groups by their resource usage.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
-
- " --order=path|tasks|cpu|memory|io\n"
- " Order by specified property\n"
- " -p Same as --order=path, order by path\n"
- " -t Same as --order=tasks, order by number of\n"
- " tasks/processes\n"
- " -c Same as --order=cpu, order by CPU load\n"
- " -m Same as --order=memory, order by memory load\n"
- " -i Same as --order=io, order by IO load\n"
- " -r --raw Provide raw (not human-readable) numbers\n"
- " --cpu[=percentage]\n"
- " Show CPU usage as percentage (default)\n"
- " --cpu=time Show CPU usage as time\n"
- " -P Count userspace processes instead of tasks (excl. kernel)\n"
- " -k Count all processes instead of tasks (incl. kernel)\n"
- " --recursive=BOOL Sum up process count recursively\n"
- " -d --delay=DELAY Delay between updates\n"
- " -n --iterations=N Run for N iterations before exiting\n"
- " -1 Shortcut for --iterations=1\n"
- " -b --batch Run in batch mode, accepting no input\n"
- " --depth=DEPTH Maximum traversal depth (default: %u)\n"
- " -M --machine= Show container\n"
- "\nSee the %s for details.\n",
+ "%sShow top control groups by their resource usage.%s\n\n",
program_invocation_short_name,
- arg_depth,
- link);
+ ansi_highlight(),
+ ansi_normal());
+
+ r = table_print_or_warn(options);
+ if (r < 0)
+ return r;
+ printf("\nSee the %s for details.\n", link);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
- enum {
- ARG_VERSION = 0x100,
- ARG_DEPTH,
- ARG_CPU_TYPE,
- ARG_ORDER,
- ARG_RECURSIVE,
- };
-
- static const struct option options[] = {
- { "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' },
- { "raw", no_argument, NULL, 'r' },
- { "depth", required_argument, NULL, ARG_DEPTH },
- { "cpu", optional_argument, NULL, ARG_CPU_TYPE },
- { "order", required_argument, NULL, ARG_ORDER },
- { "recursive", required_argument, NULL, ARG_RECURSIVE },
- { "machine", required_argument, NULL, 'M' },
- {}
- };
-
- int c, r;
-
assert(argc >= 1);
assert(argv);
- while ((c = getopt_long(argc, argv, "hptcmin:brd:kPM:1", options, NULL)) >= 0)
+ OptionParser state = { argc, argv };
+ const char *arg;
+ int r;
+ FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
- case 'h':
+ OPTION_COMMON_HELP:
return help();
- case ARG_VERSION:
+ OPTION_COMMON_VERSION:
return version();
- case ARG_ORDER:
- arg_order = order_from_string(optarg);
+ OPTION_LONG("order", "PROPERTY",
+ "Order by specified property (path, tasks, cpu, memory, io)"):
+ arg_order = order_from_string(arg);
if (arg_order < 0)
return log_error_errno(arg_order,
"Invalid argument to --order=: %s",
- optarg);
+ arg);
break;
- case 'p':
+ OPTION_SHORT('p', NULL, "Same as --order=path, order by path"):
arg_order = ORDER_PATH;
break;
- case 't':
+ OPTION_SHORT('t', NULL, "Same as --order=tasks, order by number of tasks/processes"):
arg_order = ORDER_TASKS;
break;
- case 'c':
+ OPTION_SHORT('c', NULL, "Same as --order=cpu, order by CPU load"):
arg_order = ORDER_CPU;
break;
- case 'm':
+ OPTION_SHORT('m', NULL, "Same as --order=memory, order by memory load"):
arg_order = ORDER_MEMORY;
break;
- case 'i':
+ OPTION_SHORT('i', NULL, "Same as --order=io, order by IO load"):
arg_order = ORDER_IO;
break;
- case 'r':
+ OPTION('r', "raw", NULL, "Provide raw (not human-readable) numbers"):
arg_raw = true;
break;
- case ARG_CPU_TYPE:
- if (optarg) {
- arg_cpu_type = cpu_type_from_string(optarg);
+ OPTION_LONG_FLAGS(OPTION_OPTIONAL_ARG, "cpu", "percentage|time",
+ "Show CPU usage as percentage (default) or time"):
+ if (arg) {
+ arg_cpu_type = cpu_type_from_string(arg);
if (arg_cpu_type < 0)
return log_error_errno(arg_cpu_type,
"Unknown argument to --cpu=: %s",
- optarg);
+ arg);
} else
arg_cpu_type = CPU_TIME;
-
break;
- case 'P':
+ OPTION_SHORT('P', NULL, "Count userspace processes instead of tasks (excl. kernel)"):
arg_count = COUNT_USERSPACE_PROCESSES;
break;
- case 'k':
+ OPTION_SHORT('k', NULL, "Count all processes instead of tasks (incl. kernel)"):
arg_count = COUNT_ALL_PROCESSES;
break;
- case ARG_RECURSIVE:
- r = parse_boolean_argument("--recursive=", optarg, &arg_recursive);
+ OPTION_LONG("recursive", "BOOL", "Sum up process count recursively"):
+ r = parse_boolean_argument("--recursive=", arg, &arg_recursive);
if (r < 0)
return r;
arg_recursive_unset = !r;
break;
- case 'd':
- r = parse_sec(optarg, &arg_delay);
+ OPTION('d', "delay", "DELAY", "Delay between updates"):
+ r = parse_sec(arg, &arg_delay);
if (r < 0)
- return log_error_errno(r, "Failed to parse delay parameter '%s': %m", optarg);
+ return log_error_errno(r, "Failed to parse delay parameter '%s': %m", arg);
if (arg_delay <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid delay parameter '%s'",
- optarg);
-
+ arg);
break;
- case 'n':
- r = safe_atou(optarg, &arg_iterations);
+ OPTION('n', "iterations", "N", "Run for N iterations before exiting"):
+ r = safe_atou(arg, &arg_iterations);
if (r < 0)
- return log_error_errno(r, "Failed to parse iterations parameter '%s': %m", optarg);
-
+ return log_error_errno(r, "Failed to parse iterations parameter '%s': %m", arg);
break;
- case '1':
+ OPTION_SHORT('1', NULL, "Shortcut for --iterations=1"):
arg_iterations = 1;
break;
- case 'b':
+ OPTION('b', "batch", NULL, "Run in batch mode, accepting no input"):
arg_batch = true;
break;
- case ARG_DEPTH:
- r = safe_atou(optarg, &arg_depth);
+ OPTION_LONG("depth", "DEPTH",
+ "Maximum traversal depth (default: "STRINGIFY(DEFAULT_MAXIMUM_DEPTH)")"):
+ r = safe_atou(arg, &arg_depth);
if (r < 0)
- return log_error_errno(r, "Failed to parse depth parameter '%s': %m", optarg);
-
+ return log_error_errno(r, "Failed to parse depth parameter '%s': %m", arg);
break;
- case 'M':
- arg_machine = optarg;
+ OPTION_COMMON_MACHINE:
+ arg_machine = arg;
break;
-
- case '?':
- return -EINVAL;
-
- default:
- assert_not_reached();
}
- if (optind == argc - 1)
- arg_root = argv[optind];
- else if (optind < argc)
+ size_t n_args = option_parser_get_n_args(&state);
+ if (n_args > 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Too many arguments.");
+ if (n_args == 1)
+ arg_root = option_parser_get_args(&state)[0];
return 1;
}