cgtop: convert to the new option parser

A few --help strings are changed to the common option variants.
The optional args for --unit, --user-unit, --xattr, --cgroup-id
are shown in synopsis.

A define is defined for the default of --depth to make things
clearer.

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2026-04-16 16:55:06 +02:00
parent 6132ed752a
commit 09a62b706b
+64 -104
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <signal.h>
#include <unistd.h>
@@ -10,9 +9,11 @@
#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"
@@ -72,13 +73,15 @@ typedef enum {
_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;
@@ -687,194 +690,151 @@ static void display(Hashmap *a) {
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;
}