networkctl: support edit --stdin

This commit is contained in:
Mike Yuan 2024-07-05 21:34:07 +02:00
parent 40f5c372c2
commit 119cba7835
No known key found for this signature in database
GPG Key ID: 417471C0A40F58B3
7 changed files with 45 additions and 8 deletions

View File

@ -448,6 +448,9 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
<citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for more information.</para>
<para>If <option>--stdin</option> is specified, the new content will be read from standard input.
In this mode, the old content of the file is discarded.</para>
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
</varlistentry>
@ -608,6 +611,23 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
</listitem>
</varlistentry>
<varlistentry>
<term><option>--stdin</option></term>
<listitem>
<para>When used with <command>edit</command>, 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.</para>
<para>Multiple drop-ins may be "edited" in this mode with <option>--drop-in=</option>, and
the same contents will be written to all of them. Otherwise exactly one main configuration file
is expected.</para>
<xi:include href="version-info.xml" xpointer="v257"/>
</listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="json" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />

View File

@ -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;

View File

@ -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.");

View File

@ -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;

View File

@ -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.");

View File

@ -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,

View File

@ -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" <<EOF
networkctl edit --stdin --runtime "$NETDEV_NAME" <<EOF
[NetDev]
Name=test2
Kind=dummy
EOF
networkctl cat "$NETDEV_NAME"
networkctl cat "$NETDEV_NAME" | grep -v '^# ' |
cmp - <(printf '%s\n' "[NetDev]" "Name=test2" "Kind=dummy")
cat >"/usr/lib/systemd/network/$LINK_NAME" <<EOF
[Match]