Like the command-level CommandDescription.argspec, a verb's argspec is now a nulstr, so that a verb may declare multiple alternative usage lines. The verbs help table renders one synopsis line per nulstr entry in the synopsis cell. All verb argument specifications must gain an explicit NUL suffix. This is a lot of churn, but I think this needs to be done. For now, there'll be only one user of the new functionality (i.e. a verb with more than one argspec), but I think we'll eventually want to use this in other places too.
209 lines
8.1 KiB
C
209 lines
8.1 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
|
|
#include "sd-json.h"
|
|
|
|
#include "alloc-util.h"
|
|
#include "build.h"
|
|
#include "dlopen-note.h"
|
|
#include "log.h"
|
|
#include "logs-show.h"
|
|
#include "main-func.h"
|
|
#include "networkctl.h"
|
|
#include "networkctl-address-label.h"
|
|
#include "networkctl-config-file.h"
|
|
#include "networkctl-dhcp-lease.h"
|
|
#include "networkctl-list.h"
|
|
#include "networkctl-lldp.h"
|
|
#include "networkctl-misc.h"
|
|
#include "networkctl-status-link.h"
|
|
#include "parse-argument.h"
|
|
#include "parse-util.h"
|
|
#include "path-util.h"
|
|
#include "string-util.h"
|
|
#include "verbs.h"
|
|
|
|
PagerFlags arg_pager_flags = 0;
|
|
bool arg_legend = true;
|
|
bool arg_no_reload = false;
|
|
bool arg_no_reconfigure = false;
|
|
bool arg_all = false;
|
|
bool arg_stats = false;
|
|
bool arg_full = false;
|
|
bool arg_runtime = false;
|
|
bool arg_stdin = false;
|
|
unsigned arg_lines = 10;
|
|
char *arg_drop_in = NULL;
|
|
sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
|
|
bool arg_ask_password = true;
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_drop_in, freep);
|
|
|
|
COMMAND(
|
|
"networkctl\0",
|
|
"Query and control the networking subsystem.",
|
|
.man_pages = "networkctl(1)\0",
|
|
.pager_flags = &arg_pager_flags,
|
|
);
|
|
|
|
VERB_SCOPE(, verb_list_links, "list", "[PATTERN...]\0", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY,
|
|
"List links");
|
|
VERB_SCOPE(, verb_link_status, "status", "[PATTERN...]\0", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY,
|
|
"Show link status");
|
|
VERB_SCOPE(, verb_dhcp_lease, "dhcp-lease", "INTERFACE [CODE[:FORMAT]...]\0", 2, VERB_ANY, VERB_ONLINE_ONLY,
|
|
"Show DHCP lease");
|
|
VERB_SCOPE(, verb_link_lldp_status, "lldp", "[PATTERN...]\0", 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...\0", 2, VERB_ANY, 0,
|
|
"Delete virtual netdevs");
|
|
VERB_SCOPE(, verb_link_varlink_simple_method, "up", "DEVICES...\0", 2, VERB_ANY, 0,
|
|
"Bring devices up");
|
|
VERB_SCOPE(, verb_link_varlink_simple_method, "down", "DEVICES...\0", 2, VERB_ANY, 0,
|
|
"Bring devices down");
|
|
VERB_SCOPE(, verb_link_varlink_simple_method, "renew", "DEVICES...\0", 2, VERB_ANY, VERB_ONLINE_ONLY,
|
|
"Renew dynamic configurations");
|
|
VERB_SCOPE(, verb_link_varlink_simple_method, "forcerenew", "DEVICES...\0", 2, VERB_ANY, VERB_ONLINE_ONLY,
|
|
"Trigger DHCP reconfiguration of all connected clients");
|
|
VERB_SCOPE(, verb_link_varlink_simple_method, "reconfigure", "DEVICES...\0", 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...\0", 2, VERB_ANY, 0,
|
|
"Edit network configuration files");
|
|
VERB_SCOPE(, verb_cat, "cat", "[FILES|DEVICES...]\0", 1, VERB_ANY, 0,
|
|
"Show network configuration files");
|
|
VERB_SCOPE(, verb_mask, "mask", "FILES...\0", 2, VERB_ANY, 0,
|
|
"Mask network configuration files");
|
|
VERB_SCOPE(, verb_unmask, "unmask", "FILES...\0", 2, VERB_ANY, 0,
|
|
"Unmask network configuration files");
|
|
VERB_SCOPE(, verb_persistent_storage, "persistent-storage", "BOOL\0", 2, 2, 0,
|
|
"Notify systemd-networkd if persistent storage is ready");
|
|
|
|
VERB_COMMON_HELP_AUTO_HIDDEN();
|
|
|
|
static int parse_argv(int argc, char *argv[], char ***remaining_args) {
|
|
int r;
|
|
|
|
assert(argc >= 0);
|
|
assert(argv);
|
|
assert(remaining_args);
|
|
|
|
OptionParser opts = { argc, argv };
|
|
|
|
FOREACH_OPTION_OR_RETURN(c, &opts)
|
|
switch (c) {
|
|
|
|
OPTION_COMMON_HELP:
|
|
return command_print_help();
|
|
|
|
OPTION_COMMON_VERSION:
|
|
return version();
|
|
|
|
OPTION_COMMON_NO_PAGER:
|
|
arg_pager_flags |= PAGER_DISABLE;
|
|
break;
|
|
|
|
OPTION_COMMON_NO_LEGEND:
|
|
arg_legend = false;
|
|
break;
|
|
|
|
OPTION_COMMON_NO_ASK_PASSWORD:
|
|
arg_ask_password = false;
|
|
break;
|
|
|
|
OPTION('a', "all", NULL, "Show status for all links"):
|
|
arg_all = true;
|
|
break;
|
|
|
|
OPTION('s', "stats", NULL, "Show detailed link statistics"):
|
|
arg_stats = true;
|
|
break;
|
|
|
|
OPTION('l', "full", NULL, "Do not ellipsize output"):
|
|
arg_full = true;
|
|
break;
|
|
|
|
OPTION('n', "lines", "INTEGER", "Number of journal entries to show"):
|
|
r = safe_atou(opts.arg, &arg_lines);
|
|
if (r < 0)
|
|
return log_error_errno(r, "Failed to parse --lines value '%s': %m", opts.arg);
|
|
break;
|
|
|
|
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("no-reconfigure", NULL,
|
|
"Only reload config files, do not reconfigure network interfaces"):
|
|
arg_no_reconfigure = 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(opts.arg, ".conf")) {
|
|
char *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, opts.arg);
|
|
if (r < 0)
|
|
return log_oom();
|
|
}
|
|
|
|
if (!filename_is_valid(arg_drop_in))
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
"Invalid drop-in file name '%s'.", arg_drop_in);
|
|
|
|
break;
|
|
|
|
OPTION_LONG("runtime", NULL, "Edit runtime config files"):
|
|
arg_runtime = true;
|
|
break;
|
|
|
|
OPTION_LONG("stdin", NULL, "Read new contents of edited file from stdin"):
|
|
arg_stdin = true;
|
|
break;
|
|
|
|
OPTION_COMMON_INTROSPECT_CLI:
|
|
return introspect_cli(arg_json_format_flags);
|
|
}
|
|
|
|
*remaining_args = option_parser_get_args(&opts);
|
|
return 1;
|
|
}
|
|
|
|
static int run(int argc, char* argv[]) {
|
|
char **args = NULL;
|
|
int r;
|
|
|
|
COMPRESS_JOURNAL_NOTE;
|
|
LIBSELINUX_NOTE(recommended);
|
|
|
|
log_setup();
|
|
|
|
r = parse_argv(argc, argv, &args);
|
|
if (r <= 0)
|
|
return r;
|
|
|
|
journal_browse_prepare();
|
|
|
|
return dispatch_verb(args, NULL);
|
|
}
|
|
|
|
DEFINE_MAIN_FUNCTION(run);
|