/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#include <getopt.h>
-
#include "sd-json.h"
#include "alloc-util.h"
#include "build.h"
+#include "format-table.h"
+#include "help-util.h"
#include "log.h"
#include "logs-show.h"
#include "main-func.h"
#include "networkctl-lldp.h"
#include "networkctl-misc.h"
#include "networkctl-status-link.h"
+#include "options.h"
#include "parse-argument.h"
#include "parse-util.h"
#include "path-util.h"
-#include "pretty-print.h"
#include "string-util.h"
#include "verbs.h"
STATIC_DESTRUCTOR_REGISTER(arg_drop_in, freep);
+VERB_SCOPE(, verb_list_links, "list", "[PATTERN...]", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY,
+ "List links");
+VERB_SCOPE(, verb_link_status, "status", "[PATTERN...]", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY,
+ "Show link status");
+VERB_SCOPE(, verb_link_lldp_status, "lldp", "[PATTERN...]", VERB_ANY, VERB_ANY, 0,
+ "Show LLDP neighbors");
+VERB_SCOPE(, verb_list_address_labels, "label", NULL, 1, 1, 0,
+ "Show current address label entries in the kernel");
+VERB_SCOPE(, verb_link_delete, "delete", "DEVICES...", 2, VERB_ANY, 0,
+ "Delete virtual netdevs");
+VERB_SCOPE(, verb_link_varlink_simple_method, "up", "DEVICES...", 2, VERB_ANY, 0,
+ "Bring devices up");
+VERB_SCOPE(, verb_link_varlink_simple_method, "down", "DEVICES...", 2, VERB_ANY, 0,
+ "Bring devices down");
+VERB_SCOPE(, verb_link_varlink_simple_method, "renew", "DEVICES...", 2, VERB_ANY, VERB_ONLINE_ONLY,
+ "Renew dynamic configurations");
+VERB_SCOPE(, verb_link_varlink_simple_method, "forcerenew", "DEVICES...", 2, VERB_ANY, VERB_ONLINE_ONLY,
+ "Trigger DHCP reconfiguration of all connected clients");
+VERB_SCOPE(, verb_link_varlink_simple_method, "reconfigure", "DEVICES...", 2, VERB_ANY, VERB_ONLINE_ONLY,
+ "Reconfigure interfaces");
+VERB_SCOPE(, verb_reload, "reload", NULL, 1, 1, VERB_ONLINE_ONLY,
+ "Reload .network and .netdev files");
+VERB_SCOPE(, verb_edit, "edit", "FILES|DEVICES...", 2, VERB_ANY, 0,
+ "Edit network configuration files");
+VERB_SCOPE(, verb_cat, "cat", "[FILES|DEVICES...]", 1, VERB_ANY, 0,
+ "Show network configuration files");
+VERB_SCOPE(, verb_mask, "mask", "FILES...", 2, VERB_ANY, 0,
+ "Mask network configuration files");
+VERB_SCOPE(, verb_unmask, "unmask", "FILES...", 2, VERB_ANY, 0,
+ "Unmask network configuration files");
+VERB_SCOPE(, verb_persistent_storage, "persistent-storage", "BOOL", 2, 2, 0,
+ "Notify systemd-networkd if persistent storage is ready");
+
static int help(void) {
- _cleanup_free_ char *link = NULL;
+ _cleanup_(table_unrefp) Table *verbs = NULL, *options = NULL;
int r;
- r = terminal_urlify_man("networkctl", "1", &link);
+ r = verbs_get_help_table(&verbs);
+ if (r < 0)
+ return r;
+
+ r = option_parser_get_help_table(&options);
+ if (r < 0)
+ return r;
+
+ (void) table_sync_column_widths(0, verbs, options);
+
+ help_cmdline("[OPTIONS...] COMMAND");
+ help_abstract("Query and control the networking subsystem.");
+
+ help_section("Commands");
+ r = table_print_or_warn(verbs);
+ if (r < 0)
+ return r;
+
+ help_section("Options");
+ r = table_print_or_warn(options);
if (r < 0)
- return log_oom();
-
- printf("%s [OPTIONS...] COMMAND\n\n"
- "%sQuery and control the networking subsystem.%s\n"
- "\nCommands:\n"
- " list [PATTERN...] List links\n"
- " status [PATTERN...] Show link status\n"
- " lldp [PATTERN...] Show LLDP neighbors\n"
- " label Show current address label entries in the kernel\n"
- " delete DEVICES... Delete virtual netdevs\n"
- " up DEVICES... Bring devices up\n"
- " down DEVICES... Bring devices down\n"
- " renew DEVICES... Renew dynamic configurations\n"
- " forcerenew DEVICES... Trigger DHCP reconfiguration of all connected clients\n"
- " reconfigure DEVICES... Reconfigure interfaces\n"
- " reload Reload .network and .netdev files\n"
- " edit FILES|DEVICES... Edit network configuration files\n"
- " cat [FILES|DEVICES...] Show network configuration files\n"
- " mask FILES... Mask network configuration files\n"
- " unmask FILES... Unmask network configuration files\n"
- " persistent-storage BOOL\n"
- " Notify systemd-networkd if persistent storage is ready\n"
- "\nOptions:\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " --no-pager Do not pipe output into a pager\n"
- " --no-legend Do not show the headers and footers\n"
- " --no-ask-password Do not prompt for password\n"
- " -a --all Show status for all links\n"
- " -s --stats Show detailed link statistics\n"
- " -l --full Do not ellipsize output\n"
- " -n --lines=INTEGER Number of journal entries to show\n"
- " --json=pretty|short|off\n"
- " Generate JSON output\n"
- " --no-reload Do not reload systemd-networkd or systemd-udevd\n"
- " after editing network config\n"
- " --drop-in=NAME Edit specified drop-in instead of main config file\n"
- " --runtime Edit runtime config files\n"
- " --stdin Read new contents of edited file from stdin\n"
- "\nSee the %s for details.\n",
- program_invocation_short_name,
- ansi_highlight(),
- ansi_normal(),
- link);
+ return r;
+ help_man_page_reference("networkctl", "1");
return 0;
}
-static int parse_argv(int argc, char *argv[]) {
- enum {
- ARG_VERSION = 0x100,
- ARG_NO_PAGER,
- ARG_NO_LEGEND,
- ARG_NO_ASK_PASSWORD,
- ARG_JSON,
- ARG_NO_RELOAD,
- ARG_DROP_IN,
- ARG_RUNTIME,
- ARG_STDIN,
- };
-
- static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
- { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
- { "all", no_argument, NULL, 'a' },
- { "stats", no_argument, NULL, 's' },
- { "full", no_argument, NULL, 'l' },
- { "lines", required_argument, NULL, 'n' },
- { "json", required_argument, NULL, ARG_JSON },
- { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
- { "drop-in", required_argument, NULL, ARG_DROP_IN },
- { "runtime", no_argument, NULL, ARG_RUNTIME },
- { "stdin", no_argument, NULL, ARG_STDIN },
- {}
- };
-
- int c, r;
+VERB_COMMON_HELP_HIDDEN(help);
+
+static int parse_argv(int argc, char *argv[], char ***remaining_args) {
+ int r;
assert(argc >= 0);
assert(argv);
+ assert(remaining_args);
- while ((c = getopt_long(argc, argv, "hasln:", options, NULL)) >= 0) {
+ OptionParser opts = { argc, argv };
+ FOREACH_OPTION_OR_RETURN(c, &opts)
switch (c) {
- case 'h':
+ OPTION_COMMON_HELP:
return help();
- case ARG_VERSION:
+ OPTION_COMMON_VERSION:
return version();
- case ARG_NO_PAGER:
+ OPTION_COMMON_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
- case ARG_NO_LEGEND:
+ OPTION_COMMON_NO_LEGEND:
arg_legend = false;
break;
- case ARG_NO_RELOAD:
- arg_no_reload = true;
+ OPTION_COMMON_NO_ASK_PASSWORD:
+ arg_ask_password = false;
break;
- case ARG_NO_ASK_PASSWORD:
- arg_ask_password = false;
+ OPTION('a', "all", NULL, "Show status for all links"):
+ arg_all = true;
break;
- case ARG_RUNTIME:
- arg_runtime = true;
+ OPTION('s', "stats", NULL, "Show detailed link statistics"):
+ arg_stats = true;
break;
- case ARG_STDIN:
- arg_stdin = true;
+ OPTION('l', "full", NULL, "Do not ellipsize output"):
+ arg_full = true;
+ break;
+
+ OPTION('n', "lines", "INTEGER", "Number of journal entries to show"):
+ if (safe_atou(opts.arg, &arg_lines) < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Failed to parse lines '%s'", opts.arg);
break;
- case ARG_DROP_IN:
- if (isempty(optarg))
+ OPTION_COMMON_JSON:
+ r = parse_json_argument(opts.arg, &arg_json_format_flags);
+ if (r <= 0)
+ return r;
+ break;
+
+ OPTION_LONG("no-reload", NULL,
+ "Do not reload systemd-networkd or systemd-udevd after editing network config"):
+ arg_no_reload = true;
+ break;
+
+ OPTION_LONG("drop-in", "NAME",
+ "Edit specified drop-in instead of main config file"):
+ if (isempty(opts.arg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty drop-in file name.");
- if (!endswith(optarg, ".conf")) {
+ if (!endswith(opts.arg, ".conf")) {
char *conf;
- conf = strjoin(optarg, ".conf");
+ conf = strjoin(opts.arg, ".conf");
if (!conf)
return log_oom();
free_and_replace(arg_drop_in, conf);
} else {
- r = free_and_strdup(&arg_drop_in, optarg);
+ r = free_and_strdup(&arg_drop_in, opts.arg);
if (r < 0)
return log_oom();
}
break;
- case 'a':
- arg_all = true;
- break;
-
- case 's':
- arg_stats = true;
- break;
-
- case 'l':
- arg_full = true;
- break;
-
- case 'n':
- if (safe_atou(optarg, &arg_lines) < 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to parse lines '%s'", optarg);
+ OPTION_LONG("runtime", NULL, "Edit runtime config files"):
+ arg_runtime = true;
break;
- case ARG_JSON:
- r = parse_json_argument(optarg, &arg_json_format_flags);
- if (r <= 0)
- return r;
+ OPTION_LONG("stdin", NULL, "Read new contents of edited file from stdin"):
+ arg_stdin = true;
break;
-
- case '?':
- return -EINVAL;
-
- default:
- assert_not_reached();
}
- }
+ *remaining_args = option_parser_get_args(&opts);
return 1;
}
-static int networkctl_main(int argc, char *argv[]) {
- static const Verb verbs[] = {
- { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, verb_list_links },
- { "status", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_link_status },
- { "lldp", VERB_ANY, VERB_ANY, 0, verb_link_lldp_status },
- { "label", 1, 1, 0, verb_list_address_labels },
- { "delete", 2, VERB_ANY, 0, verb_link_delete },
- { "up", 2, VERB_ANY, 0, verb_link_varlink_simple_method },
- { "down", 2, VERB_ANY, 0, verb_link_varlink_simple_method },
- { "renew", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_link_varlink_simple_method },
- { "forcerenew", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_link_varlink_simple_method },
- { "reconfigure", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_link_varlink_simple_method },
- { "reload", 1, 1, VERB_ONLINE_ONLY, verb_reload },
- { "edit", 2, VERB_ANY, 0, verb_edit },
- { "cat", 1, VERB_ANY, 0, verb_cat },
- { "mask", 2, VERB_ANY, 0, verb_mask },
- { "unmask", 2, VERB_ANY, 0, verb_unmask },
- { "persistent-storage", 2, 2, 0, verb_persistent_storage },
- {}
- };
-
- return dispatch_verb(argc, argv, verbs, NULL);
-}
-
static int run(int argc, char* argv[]) {
+ char **args = NULL;
int r;
log_setup();
- r = parse_argv(argc, argv);
+ r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
journal_browse_prepare();
- return networkctl_main(argc, argv);
+ return dispatch_verb_with_args(args, NULL);
}
DEFINE_MAIN_FUNCTION(run);