diff --git a/man/networkctl.xml b/man/networkctl.xml index 5e2126ff218..e47cf5895cf 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -448,6 +448,9 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR) systemd.link5 for more information. + If is specified, the new content will be read from standard input. + In this mode, the old content of the file is discarded. + @@ -608,6 +611,23 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR) + + + + + When used with edit, the contents of the file will be read from standard + input and the editor will not be launched. In this mode, the old contents of the file are + automatically replaced. This is useful to "edit" configuration from scripts, especially so that + drop-in directories are created and populated in one go. + + Multiple drop-ins may be "edited" in this mode with , and + the same contents will be written to all of them. Otherwise exactly one main configuration file + is expected. + + + + + diff --git a/src/network/networkctl-config-file.c b/src/network/networkctl-config-file.c index 216e9d49543..1aa03619b72 100644 --- a/src/network/networkctl-config-file.c +++ b/src/network/networkctl-config-file.c @@ -396,23 +396,30 @@ static int reload_daemons(ReloadFlags flags) { } int verb_edit(int argc, char *argv[], void *userdata) { + char **args = ASSERT_PTR(strv_skip(argv, 1)); _cleanup_(edit_file_context_done) EditFileContext context = { .marker_start = DROPIN_MARKER_START, .marker_end = DROPIN_MARKER_END, .remove_parent = !!arg_drop_in, + .stdin = arg_stdin, }; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; ReloadFlags reload = 0; int r; - if (!on_tty()) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit network config files if not on a tty."); + if (!on_tty() && !arg_stdin) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit network config files interactively if not on a tty."); + + /* Duplicating main configs makes no sense. This also mimics the behavior of systemctl. */ + if (arg_stdin && !arg_drop_in && strv_length(args) != 1) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "When 'edit --stdin' without '--drop-in=', exactly one config file for editing must be specified."); r = mac_selinux_init(); if (r < 0) return r; - STRV_FOREACH(name, strv_skip(argv, 1)) { + STRV_FOREACH(name, args) { _cleanup_strv_free_ char **dropins = NULL; _cleanup_free_ char *path = NULL; const char *link_config; diff --git a/src/network/networkctl.c b/src/network/networkctl.c index b51c7aa7e59..6c96a84c46b 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -91,6 +91,7 @@ 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; @@ -3025,6 +3026,7 @@ static int help(void) { " 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(), @@ -3043,6 +3045,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_NO_RELOAD, ARG_DROP_IN, ARG_RUNTIME, + ARG_STDIN, }; static const struct option options[] = { @@ -3058,6 +3061,7 @@ static int parse_argv(int argc, char *argv[]) { { "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 }, {} }; @@ -3092,6 +3096,10 @@ static int parse_argv(int argc, char *argv[]) { arg_runtime = true; break; + case ARG_STDIN: + arg_stdin = true; + break; + case ARG_DROP_IN: if (isempty(optarg)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty drop-in file name."); diff --git a/src/network/networkctl.h b/src/network/networkctl.h index 1765a8f83df..d44ee8173e0 100644 --- a/src/network/networkctl.h +++ b/src/network/networkctl.h @@ -15,6 +15,7 @@ extern bool arg_all; extern bool arg_stats; extern bool arg_full; extern bool arg_runtime; +extern bool arg_stdin; extern unsigned arg_lines; extern char *arg_drop_in; extern sd_json_format_flags_t arg_json_format_flags; diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c index 15398f83646..b7bd3851fd0 100644 --- a/src/systemctl/systemctl-edit.c +++ b/src/systemctl/systemctl-edit.c @@ -323,7 +323,7 @@ int verb_edit(int argc, char *argv[], void *userdata) { int r; if (!on_tty() && !arg_stdin) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units if not on a tty."); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units interactively if not on a tty."); if (arg_transport != BUS_TRANSPORT_LOCAL) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units remotely."); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 1e36455cf21..912c1d83017 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -347,7 +347,7 @@ static int systemctl_help(void) { " --drop-in=NAME Edit unit files using the specified drop-in file name\n" " --when=TIME Schedule halt/power-off/reboot/kexec action after\n" " a certain timestamp\n" - " --stdin Read contents of edited file from stdin\n" + " --stdin Read new contents of edited file from stdin\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, diff --git a/test/units/TEST-74-AUX-UTILS.networkctl.sh b/test/units/TEST-74-AUX-UTILS.networkctl.sh index 3e333a2eabe..8c62de9155a 100755 --- a/test/units/TEST-74-AUX-UTILS.networkctl.sh +++ b/test/units/TEST-74-AUX-UTILS.networkctl.sh @@ -11,7 +11,7 @@ at_exit() { systemctl stop systemd-networkd if [[ -v NETWORK_NAME && -v NETDEV_NAME && -v LINK_NAME ]]; then - rm -fvr {/usr/lib,/etc,/run}/systemd/network/"$NETWORK_NAME" "/usr/lib/systemd/network/$NETDEV_NAME" \ + rm -fvr {/usr/lib,/etc,/run}/systemd/network/"$NETWORK_NAME" "/run/lib/systemd/network/$NETDEV_NAME" \ {/usr/lib,/etc}/systemd/network/"$LINK_NAME" "/etc/systemd/network/${NETWORK_NAME}.d" \ "new" "+4" fi @@ -75,13 +75,14 @@ cmp "+4" "/etc/systemd/network/${NETWORK_NAME}.d/test.conf" networkctl cat "$NETWORK_NAME" | grep '^# ' | cmp - <(printf '%s\n' "# /etc/systemd/network/$NETWORK_NAME" "# /etc/systemd/network/${NETWORK_NAME}.d/test.conf") -cat >"/usr/lib/systemd/network/$NETDEV_NAME" <"/usr/lib/systemd/network/$LINK_NAME" <