mirror of
https://github.com/systemd/systemd
synced 2024-10-14 20:17:52 +00:00
networkctl: introduce verb mask and unmask
Suggested in https://github.com/systemd/systemd/pull/29928#discussion_r1386626565
This commit is contained in:
parent
7ce6a0960f
commit
28bb29cbb4
|
@ -461,6 +461,40 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
|
|||
|
||||
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<command>mask</command>
|
||||
<replaceable>FILE</replaceable>…
|
||||
</term>
|
||||
<listitem><para>Mask network configuration files, which include <filename>.network</filename>,
|
||||
<filename>.netdev</filename>, and <filename>.link</filename> files. A symlink of the given name will
|
||||
be created under <filename>/etc/</filename> or <filename>/run/</filename>, depending on
|
||||
whether <option>--runtime</option> is specified, that points to <filename>/dev/null</filename>.
|
||||
If a non-empty config file with the specified name exists under the target directory or a directory
|
||||
with higher priority (e.g. <option>--runtime</option> is used while an existing config resides
|
||||
in <filename>/etc/</filename>), the operation is aborted.</para>
|
||||
|
||||
<para>This command honors <option>--no-reload</option> in the same way as <command>edit</command>.
|
||||
</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<command>unmask</command>
|
||||
<replaceable>FILE</replaceable>…
|
||||
</term>
|
||||
<listitem><para>Unmask network configuration files, i.e. reverting the effect of <command>mask</command>.
|
||||
Note that this command operates regardless of the scope of the directory, i.e. <option>--runtime</option>
|
||||
is of no effect.</para>
|
||||
|
||||
<para>This command honors <option>--no-reload</option> in the same way as <command>edit</command>
|
||||
and <command>mask</command>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -534,11 +568,11 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
|
|||
<term><option>--no-reload</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>When used with <command>edit</command>,
|
||||
<para>When used with <command>edit</command>, <command>mask</command>, or <command>unmask</command>,
|
||||
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
or
|
||||
<citerefentry><refentrytitle>systemd-udevd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
will not be reloaded after the editing finishes.</para>
|
||||
will not be reloaded after the operation finishes.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v254"/>
|
||||
</listitem>
|
||||
|
@ -547,8 +581,8 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
|
|||
<term><option>--runtime</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>When used with <command>edit</command>, edit the file under <filename>/run/</filename>
|
||||
instead of <filename>/etc/</filename>.</para>
|
||||
<para>When used with <command>edit</command> or <command>mask</command>,
|
||||
operate on the file under <filename>/run/</filename> instead of <filename>/etc/</filename>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "bus-wait-for-jobs.h"
|
||||
#include "conf-files.h"
|
||||
#include "edit-util.h"
|
||||
#include "mkdir-label.h"
|
||||
#include "netlink-util.h"
|
||||
#include "networkctl.h"
|
||||
#include "networkctl-config-file.h"
|
||||
|
@ -518,3 +519,110 @@ int verb_cat(int argc, char *argv[], void *userdata) {
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int verb_mask(int argc, char *argv[], void *userdata) {
|
||||
ReloadFlags flags = 0;
|
||||
int r;
|
||||
|
||||
r = mac_selinux_init();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(name, strv_skip(argv, 1)) {
|
||||
_cleanup_free_ char *config_path = NULL, *symlink_path = NULL;
|
||||
ReloadFlags reload;
|
||||
|
||||
/* We update the real 'flags' at last, since the operation can be skipped. */
|
||||
if (ENDSWITH_SET(*name, ".network", ".netdev"))
|
||||
reload = RELOAD_NETWORKD;
|
||||
else if (endswith(*name, ".link"))
|
||||
reload = RELOAD_UDEVD;
|
||||
else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid network config name '%s'.", *name);
|
||||
|
||||
r = get_config_files_by_name(*name, /* allow_masked = */ true, &config_path, /* ret_dropins = */ NULL);
|
||||
if (r == -ENOENT)
|
||||
log_warning("No existing network config '%s' found, proceeding anyway.", *name);
|
||||
else if (r < 0)
|
||||
return log_error_errno(r, "Failed to get the path of network config '%s': %m", *name);
|
||||
else if (!path_startswith(config_path, "/usr")) {
|
||||
r = null_or_empty_path(config_path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r,
|
||||
"Failed to check if '%s' is masked: %m", config_path);
|
||||
if (r > 0) {
|
||||
log_debug("%s is already masked, skipping.", config_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* At this point, we have found a config under mutable dir (/run/ or /etc/),
|
||||
* so masking through /run/ (--runtime) is not possible. If it's under /etc/,
|
||||
* then it doesn't work without --runtime either. */
|
||||
if (arg_runtime || path_startswith(config_path, "/etc"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
|
||||
"Cannot mask network config %s: %s exists",
|
||||
*name, config_path);
|
||||
}
|
||||
|
||||
symlink_path = path_join(NETWORK_DIRS[arg_runtime ? 1 : 0], *name);
|
||||
if (!symlink_path)
|
||||
return log_oom();
|
||||
|
||||
(void) mkdir_parents_label(symlink_path, 0755);
|
||||
|
||||
if (symlink("/dev/null", symlink_path) < 0)
|
||||
return log_error_errno(errno,
|
||||
"Failed to create symlink '%s' to /dev/null: %m", symlink_path);
|
||||
|
||||
flags |= reload;
|
||||
log_info("Successfully created symlink '%s' to /dev/null.", symlink_path);
|
||||
}
|
||||
|
||||
return reload_daemons(flags);
|
||||
}
|
||||
|
||||
int verb_unmask(int argc, char *argv[], void *userdata) {
|
||||
ReloadFlags flags = 0;
|
||||
int r;
|
||||
|
||||
STRV_FOREACH(name, strv_skip(argv, 1)) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
ReloadFlags reload;
|
||||
|
||||
if (ENDSWITH_SET(*name, ".network", ".netdev"))
|
||||
reload = RELOAD_NETWORKD;
|
||||
else if (endswith(*name, ".link"))
|
||||
reload = RELOAD_UDEVD;
|
||||
else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid network config name '%s'.", *name);
|
||||
|
||||
r = get_config_files_by_name(*name, /* allow_masked = */ true, &path, /* ret_dropins = */ NULL);
|
||||
if (r == -ENOENT) {
|
||||
log_debug_errno(r, "Network configuration '%s' doesn't exist, skipping.", *name);
|
||||
continue;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get the path of network config '%s': %m", *name);
|
||||
|
||||
r = null_or_empty_path(path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to check if '%s' is masked: %m", path);
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
if (path_startswith(path, "/usr"))
|
||||
return log_error_errno(r, "Cannot unmask network config under /usr/: %s", path);
|
||||
|
||||
if (unlink(path) < 0) {
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
|
||||
return log_error_errno(errno, "Failed to remove '%s': %m", path);
|
||||
}
|
||||
|
||||
flags |= reload;
|
||||
log_info("Successfully removed masked network config '%s'.", path);
|
||||
}
|
||||
|
||||
return reload_daemons(flags);
|
||||
}
|
||||
|
|
|
@ -3,3 +3,6 @@
|
|||
|
||||
int verb_edit(int argc, char *argv[], void *userdata);
|
||||
int verb_cat(int argc, char *argv[], void *userdata);
|
||||
|
||||
int verb_mask(int argc, char *argv[], void *userdata);
|
||||
int verb_unmask(int argc, char *argv[], void *userdata);
|
||||
|
|
|
@ -2877,6 +2877,8 @@ static int help(void) {
|
|||
" 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"
|
||||
"\nOptions:\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
|
@ -3033,6 +3035,8 @@ static int networkctl_main(int argc, char *argv[]) {
|
|||
{ "reload", 1, 1, VERB_ONLINE_ONLY, verb_reload },
|
||||
{ "edit", 2, VERB_ANY, 0, verb_edit },
|
||||
{ "cat", 2, VERB_ANY, 0, verb_cat },
|
||||
{ "mask", 2, VERB_ANY, 0, verb_mask },
|
||||
{ "unmask", 2, VERB_ANY, 0, verb_unmask },
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -28,6 +28,16 @@ Name=test
|
|||
EOF
|
||||
|
||||
# Test files
|
||||
|
||||
networkctl mask --runtime "donotexist.network"
|
||||
assert_eq "$(readlink /run/systemd/network/donotexist.network)" "/dev/null"
|
||||
networkctl unmask "donotexist.network" # unmask should work even without --runtime
|
||||
[[ ! -e /run/systemd/network/donotexist.network ]]
|
||||
|
||||
touch /usr/lib/systemd/network/donotexist.network
|
||||
(! networkctl unmask "donotexist.network")
|
||||
rm /usr/lib/systemd/network/donotexist.network
|
||||
|
||||
networkctl cat "$NETWORK_NAME" | tail -n +2 | cmp - "/usr/lib/systemd/network/$NETWORK_NAME"
|
||||
|
||||
cat >new <<EOF
|
||||
|
@ -36,11 +46,20 @@ Name=test2
|
|||
EOF
|
||||
|
||||
EDITOR='mv new' script -ec 'networkctl edit --runtime "$NETWORK_NAME"' /dev/null
|
||||
(! networkctl mask --runtime "$NETWORK_NAME")
|
||||
printf '%s\n' '[Match]' 'Name=test2' | cmp - "/run/systemd/network/$NETWORK_NAME"
|
||||
|
||||
networkctl mask "$NETWORK_NAME"
|
||||
assert_eq "$(readlink "/etc/systemd/network/$NETWORK_NAME")" "/dev/null"
|
||||
(! networkctl edit "$NETWORK_NAME")
|
||||
(! networkctl edit --runtime "$NETWORK_NAME")
|
||||
(! networkctl cat "$NETWORK_NAME")
|
||||
networkctl unmask "$NETWORK_NAME"
|
||||
|
||||
EDITOR='true' script -ec 'networkctl edit "$NETWORK_NAME"' /dev/null
|
||||
printf '%s\n' '[Match]' 'Name=test2' | cmp - "/etc/systemd/network/$NETWORK_NAME"
|
||||
|
||||
(! networkctl mask "$NETWORK_NAME")
|
||||
(! EDITOR='true' script -ec 'networkctl edit --runtime "$NETWORK_NAME"' /dev/null)
|
||||
|
||||
cat >"+4" <<EOF
|
||||
|
|
Loading…
Reference in a new issue