mirror of
https://github.com/systemd/systemd
synced 2025-10-03 10:44:44 +02:00
Compare commits
22 Commits
da46a1bc3c
...
407234203b
Author | SHA1 | Date | |
---|---|---|---|
![]() |
407234203b | ||
![]() |
370d3c31b4 | ||
![]() |
9706d27cbe | ||
![]() |
1b153a82f4 | ||
![]() |
b4e9c97477 | ||
![]() |
01584bf9e4 | ||
![]() |
d9e2af0ae8 | ||
![]() |
c4febde9d0 | ||
![]() |
1d61d70abb | ||
![]() |
80271a446c | ||
![]() |
a70581ffb5 | ||
![]() |
54c2459d56 | ||
![]() |
a959cd2812 | ||
![]() |
66d2330265 | ||
![]() |
5288861bf6 | ||
![]() |
a34e58d445 | ||
![]() |
ab7153b3f4 | ||
![]() |
3be9d62ad1 | ||
![]() |
24e3ed843f | ||
![]() |
44e1f7e3dc | ||
![]() |
d23a66f274 | ||
![]() |
3b5a4fc685 |
@ -2693,6 +2693,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateMounts = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateIPC = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s ProtectHome = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s ProtectSystem = '...';
|
||||
@ -2777,6 +2779,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s NetworkNamespacePath = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s IPCNamespacePath = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s KillMode = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly i KillSignal = ...;
|
||||
@ -3194,6 +3198,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<!--property PrivateMounts is not documented!-->
|
||||
|
||||
<!--property PrivateIPC is not documented!-->
|
||||
|
||||
<!--property ProtectHome is not documented!-->
|
||||
|
||||
<!--property ProtectSystem is not documented!-->
|
||||
@ -3278,6 +3284,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<!--property NetworkNamespacePath is not documented!-->
|
||||
|
||||
<!--property IPCNamespacePath is not documented!-->
|
||||
|
||||
<!--property KillMode is not documented!-->
|
||||
|
||||
<!--property KillSignal is not documented!-->
|
||||
@ -3772,6 +3780,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateMounts"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateIPC"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ProtectHome"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/>
|
||||
@ -3856,6 +3866,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
||||
@ -4454,6 +4466,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateMounts = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateIPC = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s ProtectHome = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s ProtectSystem = '...';
|
||||
@ -4538,6 +4552,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s NetworkNamespacePath = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s IPCNamespacePath = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s KillMode = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly i KillSignal = ...;
|
||||
@ -4983,6 +4999,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<!--property PrivateMounts is not documented!-->
|
||||
|
||||
<!--property PrivateIPC is not documented!-->
|
||||
|
||||
<!--property ProtectHome is not documented!-->
|
||||
|
||||
<!--property ProtectSystem is not documented!-->
|
||||
@ -5067,6 +5085,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<!--property NetworkNamespacePath is not documented!-->
|
||||
|
||||
<!--property IPCNamespacePath is not documented!-->
|
||||
|
||||
<!--property KillMode is not documented!-->
|
||||
|
||||
<!--property KillSignal is not documented!-->
|
||||
@ -5559,6 +5579,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateMounts"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateIPC"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ProtectHome"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/>
|
||||
@ -5643,6 +5665,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
||||
@ -6143,6 +6167,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateMounts = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateIPC = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s ProtectHome = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s ProtectSystem = '...';
|
||||
@ -6227,6 +6253,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s NetworkNamespacePath = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s IPCNamespacePath = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s KillMode = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly i KillSignal = ...;
|
||||
@ -6600,6 +6628,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<!--property PrivateMounts is not documented!-->
|
||||
|
||||
<!--property PrivateIPC is not documented!-->
|
||||
|
||||
<!--property ProtectHome is not documented!-->
|
||||
|
||||
<!--property ProtectSystem is not documented!-->
|
||||
@ -6684,6 +6714,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<!--property NetworkNamespacePath is not documented!-->
|
||||
|
||||
<!--property IPCNamespacePath is not documented!-->
|
||||
|
||||
<!--property KillMode is not documented!-->
|
||||
|
||||
<!--property KillSignal is not documented!-->
|
||||
@ -7094,6 +7126,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateMounts"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateIPC"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ProtectHome"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/>
|
||||
@ -7178,6 +7212,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
||||
@ -7799,6 +7835,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateMounts = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateIPC = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s ProtectHome = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s ProtectSystem = '...';
|
||||
@ -7883,6 +7921,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s NetworkNamespacePath = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s IPCNamespacePath = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s KillMode = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly i KillSignal = ...;
|
||||
@ -8242,6 +8282,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
|
||||
<!--property PrivateMounts is not documented!-->
|
||||
|
||||
<!--property PrivateIPC is not documented!-->
|
||||
|
||||
<!--property ProtectHome is not documented!-->
|
||||
|
||||
<!--property ProtectSystem is not documented!-->
|
||||
@ -8326,6 +8368,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
|
||||
<!--property NetworkNamespacePath is not documented!-->
|
||||
|
||||
<!--property IPCNamespacePath is not documented!-->
|
||||
|
||||
<!--property KillMode is not documented!-->
|
||||
|
||||
<!--property KillSignal is not documented!-->
|
||||
@ -8722,6 +8766,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateMounts"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateIPC"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ProtectHome"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/>
|
||||
@ -8806,6 +8852,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
|
||||
|
@ -1603,6 +1603,53 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>PrivateIPC=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. If true, sets up a new IPC namespace for the executed processes.
|
||||
Each IPC namespace has its own set of System V IPC identifiers and its own POSIX message queue file system.
|
||||
This is useful to avoid name clash of IPC identifiers. Defaults to false. It is possible to run two or
|
||||
more units within the same private IPC namespace by using the <varname>JoinsNamespaceOf=</varname> directive,
|
||||
see <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details.</para>
|
||||
|
||||
<para>Note that IPC namespacing does not have an effect on
|
||||
<constant>AF_UNIX</constant> sockets, which are the most common
|
||||
form of IPC used on Linux. Instead, <constant>AF_UNIX</constant>
|
||||
sockets in the file system are subject to mount namespacing, and
|
||||
those in the abstract namespace are subject to network namespacing.
|
||||
IPC namespacing only has an effect on SysV IPC (which is mostly
|
||||
legacy) as well as POSIX message queues (for which
|
||||
<constant>AF_UNIX</constant>/<constant>SOCK_SEQPACKET</constant>
|
||||
sockets are typically a better replacement). IPC namespacing also
|
||||
has no effect on POSIX shared memory (which is subject to mount
|
||||
namespacing) either. See
|
||||
<citerefentry><refentrytitle>ipc_namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
||||
the details.</para>
|
||||
|
||||
<para>Note that the implementation of this setting might be impossible (for example if IPC namespaces are
|
||||
not available), and the unit should be written in a way that does not solely rely on this setting for
|
||||
security.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>IPCNamespacePath=</varname></term>
|
||||
|
||||
<listitem><para>Takes an absolute file system path refererring to a Linux IPC namespace
|
||||
pseudo-file (i.e. a file like <filename>/proc/$PID/ns/ipc</filename> or a bind mount or symlink to
|
||||
one). When set the invoked processes are added to the network namespace referenced by that path. The
|
||||
path has to point to a valid namespace file at the moment the processes are forked off. If this
|
||||
option is used <varname>PrivateIPC=</varname> has no effect. If this option is used together with
|
||||
<varname>JoinsNamespaceOf=</varname> then it only has an effect if this unit is started before any of
|
||||
the listed units that have <varname>PrivateIPC=</varname> or
|
||||
<varname>IPCNamespacePath=</varname> configured, as otherwise the network namespace of those
|
||||
units is reused.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>PrivateUsers=</varname></term>
|
||||
|
||||
@ -3585,7 +3632,7 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
|
||||
<row>
|
||||
<entry>226</entry>
|
||||
<entry><constant>EXIT_NAMESPACE</constant></entry>
|
||||
<entry>Failed to set up mount namespacing. See <varname>ReadOnlyPaths=</varname> and related settings above.</entry>
|
||||
<entry>Failed to set up mount, UTS, or IPC namespacing. See <varname>ReadOnlyPaths=</varname>, <varname>ProtectHostname=</varname>, <varname>PrivateIPC=</varname>, and related settings above.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>227</entry>
|
||||
|
@ -799,14 +799,16 @@
|
||||
|
||||
<listitem><para>For units that start processes (such as service units), lists one or more other units
|
||||
whose network and/or temporary file namespace to join. This only applies to unit types which support
|
||||
the <varname>PrivateNetwork=</varname>, <varname>NetworkNamespacePath=</varname> and
|
||||
the <varname>PrivateNetwork=</varname>, <varname>NetworkNamespacePath=</varname>,
|
||||
<varname>PrivateIPC=</varname>, <varname>IPCNamespacePath=</varname>, and
|
||||
<varname>PrivateTmp=</varname> directives (see
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details). If a unit that has this setting set is started, its processes will see the same
|
||||
<filename>/tmp/</filename>, <filename>/var/tmp/</filename> and network namespace as one listed unit
|
||||
that is started. If multiple listed units are already started, it is not defined which namespace is
|
||||
joined. Note that this setting only has an effect if
|
||||
<varname>PrivateNetwork=</varname>/<varname>NetworkNamespacePath=</varname> and/or
|
||||
<filename>/tmp/</filename>, <filename>/var/tmp/</filename>, IPC namespace and network namespace as
|
||||
one listed unit that is started. If multiple listed units are already started, it is not defined
|
||||
which namespace is joined. Note that this setting only has an effect if
|
||||
<varname>PrivateNetwork=</varname>/<varname>NetworkNamespacePath=</varname>,
|
||||
<varname>PrivateIPC=</varname>/<varname>IPCNamespacePath=</varname> and/or
|
||||
<varname>PrivateTmp=</varname> is enabled for both the unit that joins the namespace and the unit
|
||||
whose namespace is joined.</para></listitem>
|
||||
</varlistentry>
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -159,24 +158,42 @@ int pipe_eof(int fd) {
|
||||
return !!(r & POLLHUP);
|
||||
}
|
||||
|
||||
int fd_wait_for_event(int fd, int event, usec_t t) {
|
||||
|
||||
struct pollfd pollfd = {
|
||||
.fd = fd,
|
||||
.events = event,
|
||||
};
|
||||
|
||||
int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) {
|
||||
struct timespec ts;
|
||||
int r;
|
||||
|
||||
r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
|
||||
assert(fds || nfds == 0);
|
||||
|
||||
if (nfds == 0)
|
||||
return 0;
|
||||
|
||||
r = ppoll(fds, nfds, timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
if (pollfd.revents & POLLNVAL)
|
||||
for (size_t i = 0, n = r; i < nfds && n > 0; i++) {
|
||||
if (fds[i].revents == 0)
|
||||
continue;
|
||||
if (fds[i].revents & POLLNVAL)
|
||||
return -EBADF;
|
||||
n--;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int fd_wait_for_event(int fd, int event, usec_t timeout) {
|
||||
struct pollfd pollfd = {
|
||||
.fd = fd,
|
||||
.events = event,
|
||||
};
|
||||
int r;
|
||||
|
||||
r = ppoll_usec(&pollfd, 1, timeout);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
return pollfd.revents;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@ -18,6 +19,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
|
||||
|
||||
int pipe_eof(int fd);
|
||||
|
||||
int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout);
|
||||
int fd_wait_for_event(int fd, int event, usec_t timeout);
|
||||
|
||||
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
|
||||
|
@ -125,13 +125,13 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
|
||||
return reset_uid_gid();
|
||||
}
|
||||
|
||||
int fd_is_network_ns(int fd) {
|
||||
int fd_is_ns(int fd, unsigned long nsflag) {
|
||||
struct statfs s;
|
||||
int r;
|
||||
|
||||
/* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
|
||||
* way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
|
||||
* this somewhat nicely.
|
||||
/* Checks whether the specified file descriptor refers to a namespace created by specifying nsflag in clone().
|
||||
* On old kernels there's no nice way to detect that, hence on those we'll return a recognizable error (EUCLEAN),
|
||||
* so that callers can handle this somewhat nicely.
|
||||
*
|
||||
* This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
|
||||
* refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
|
||||
@ -168,7 +168,7 @@ int fd_is_network_ns(int fd) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return r == CLONE_NEWNET;
|
||||
return (unsigned long) r == nsflag;
|
||||
}
|
||||
|
||||
int detach_mount_namespace(void) {
|
||||
|
@ -6,6 +6,6 @@
|
||||
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
|
||||
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
|
||||
|
||||
int fd_is_network_ns(int fd);
|
||||
int fd_is_ns(int fd, unsigned long nsflag);
|
||||
|
||||
int detach_mount_namespace(void);
|
||||
|
@ -1162,6 +1162,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("PrivateUsers", "b", bus_property_get_bool, offsetof(ExecContext, private_users), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("PrivateMounts", "b", bus_property_get_bool, offsetof(ExecContext, private_mounts), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("PrivateIPC", "b", bus_property_get_bool, offsetof(ExecContext, private_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ProtectHome", "s", property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ProtectSystem", "s", property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@ -1204,6 +1205,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_PROPERTY("ProcSubset", "s", property_get_proc_subset, offsetof(ExecContext, proc_subset), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ProtectHostname", "b", bus_property_get_bool, offsetof(ExecContext, protect_hostname), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("IPCNamespacePath", "s", NULL, offsetof(ExecContext, ipc_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
|
||||
/* Obsolete/redundant properties: */
|
||||
SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
|
||||
@ -1753,6 +1755,9 @@ int bus_exec_context_set_transient_property(
|
||||
if (streq(name, "PrivateNetwork"))
|
||||
return bus_set_transient_bool(u, name, &c->private_network, message, flags, error);
|
||||
|
||||
if (streq(name, "PrivateIPC"))
|
||||
return bus_set_transient_bool(u, name, &c->private_ipc, message, flags, error);
|
||||
|
||||
if (streq(name, "PrivateUsers"))
|
||||
return bus_set_transient_bool(u, name, &c->private_users, message, flags, error);
|
||||
|
||||
@ -1873,6 +1878,9 @@ int bus_exec_context_set_transient_property(
|
||||
if (streq(name, "NetworkNamespacePath"))
|
||||
return bus_set_transient_path(u, name, &c->network_namespace_path, message, flags, error);
|
||||
|
||||
if (streq(name, "IPCNamespacePath"))
|
||||
return bus_set_transient_path(u, name, &c->ipc_namespace_path, message, flags, error);
|
||||
|
||||
if (streq(name, "SupplementaryGroups")) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
char **p;
|
||||
|
@ -2037,7 +2037,9 @@ bool exec_needs_mount_namespace(
|
||||
context->protect_kernel_logs ||
|
||||
context->protect_control_groups ||
|
||||
context->protect_proc != PROTECT_PROC_DEFAULT ||
|
||||
context->proc_subset != PROC_SUBSET_ALL)
|
||||
context->proc_subset != PROC_SUBSET_ALL ||
|
||||
context->private_ipc ||
|
||||
context->ipc_namespace_path)
|
||||
return true;
|
||||
|
||||
if (context->root_directory) {
|
||||
@ -3178,6 +3180,7 @@ static int apply_mount_namespace(
|
||||
.protect_system = context->protect_system,
|
||||
.protect_proc = context->protect_proc,
|
||||
.proc_subset = context->proc_subset,
|
||||
.private_ipc = context->private_ipc || context->ipc_namespace_path,
|
||||
};
|
||||
} else if (!context->dynamic_user && root_dir)
|
||||
/*
|
||||
@ -3476,8 +3479,10 @@ static int close_remaining_fds(
|
||||
n_dont_close += n_fds;
|
||||
}
|
||||
|
||||
if (runtime)
|
||||
if (runtime) {
|
||||
append_socket_pair(dont_close, &n_dont_close, runtime->netns_storage_socket);
|
||||
append_socket_pair(dont_close, &n_dont_close, runtime->ipcns_storage_socket);
|
||||
}
|
||||
|
||||
if (dcreds) {
|
||||
if (dcreds->user)
|
||||
@ -3918,13 +3923,21 @@ static int exec_child(
|
||||
}
|
||||
|
||||
if (context->network_namespace_path && runtime && runtime->netns_storage_socket[0] >= 0) {
|
||||
r = open_netns_path(runtime->netns_storage_socket, context->network_namespace_path);
|
||||
r = open_shareable_ns_path(runtime->netns_storage_socket, context->network_namespace_path, CLONE_NEWNET);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_NETWORK;
|
||||
return log_unit_error_errno(unit, r, "Failed to open network namespace path %s: %m", context->network_namespace_path);
|
||||
}
|
||||
}
|
||||
|
||||
if (context->ipc_namespace_path && runtime && runtime->ipcns_storage_socket[0] >= 0) {
|
||||
r = open_shareable_ns_path(runtime->ipcns_storage_socket, context->ipc_namespace_path, CLONE_NEWIPC);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_NAMESPACE;
|
||||
return log_unit_error_errno(unit, r, "Failed to open IPC namespace path %s: %m", context->ipc_namespace_path);
|
||||
}
|
||||
}
|
||||
|
||||
r = setup_input(context, params, socket_fd, named_iofds);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_STDIN;
|
||||
@ -4195,7 +4208,7 @@ static int exec_child(
|
||||
if ((context->private_network || context->network_namespace_path) && runtime && runtime->netns_storage_socket[0] >= 0) {
|
||||
|
||||
if (ns_type_supported(NAMESPACE_NET)) {
|
||||
r = setup_netns(runtime->netns_storage_socket);
|
||||
r = setup_shareable_ns(runtime->netns_storage_socket, CLONE_NEWNET);
|
||||
if (r == -EPERM)
|
||||
log_unit_warning_errno(unit, r,
|
||||
"PrivateNetwork=yes is configured, but network namespace setup failed, ignoring: %m");
|
||||
@ -4211,6 +4224,25 @@ static int exec_child(
|
||||
log_unit_warning(unit, "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring.");
|
||||
}
|
||||
|
||||
if ((context->private_ipc || context->ipc_namespace_path) && runtime && runtime->ipcns_storage_socket[0] >= 0) {
|
||||
|
||||
if (ns_type_supported(NAMESPACE_IPC)) {
|
||||
r = setup_shareable_ns(runtime->ipcns_storage_socket, CLONE_NEWIPC);
|
||||
if (r == -EPERM)
|
||||
log_unit_warning_errno(unit, r,
|
||||
"PrivateIPC=yes is configured, but IPC namespace setup failed, ignoring: %m");
|
||||
else if (r < 0) {
|
||||
*exit_status = EXIT_NAMESPACE;
|
||||
return log_unit_error_errno(unit, r, "Failed to set up IPC namespacing: %m");
|
||||
}
|
||||
} else if (context->ipc_namespace_path) {
|
||||
*exit_status = EXIT_NAMESPACE;
|
||||
return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"IPCNamespacePath= is not supported, refusing.");
|
||||
} else
|
||||
log_unit_warning(unit, "PrivateIPC=yes is configured, but the kernel does not support IPC namespaces, ignoring.");
|
||||
}
|
||||
|
||||
needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
|
||||
if (needs_mount_namespace) {
|
||||
_cleanup_free_ char *error_path = NULL;
|
||||
@ -4314,7 +4346,7 @@ static int exec_child(
|
||||
#endif
|
||||
|
||||
/* We repeat the fd closing here, to make sure that nothing is leaked from the PAM modules. Note that we are
|
||||
* more aggressive this time since socket_fd and the netns fds we don't need anymore. We do keep the exec_fd
|
||||
* more aggressive this time since socket_fd and the netns and ipcns fds we don't need anymore. We do keep the exec_fd
|
||||
* however if we have it as we want to keep it open until the final execve(). */
|
||||
|
||||
r = close_all_fds(keep_fds, n_keep_fds);
|
||||
@ -6057,6 +6089,7 @@ static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
|
||||
rt->tmp_dir = mfree(rt->tmp_dir);
|
||||
rt->var_tmp_dir = mfree(rt->var_tmp_dir);
|
||||
safe_close_pair(rt->netns_storage_socket);
|
||||
safe_close_pair(rt->ipcns_storage_socket);
|
||||
return mfree(rt);
|
||||
}
|
||||
|
||||
@ -6081,6 +6114,7 @@ static int exec_runtime_allocate(ExecRuntime **ret, const char *id) {
|
||||
*n = (ExecRuntime) {
|
||||
.id = TAKE_PTR(id_copy),
|
||||
.netns_storage_socket = { -1, -1 },
|
||||
.ipcns_storage_socket = { -1, -1 },
|
||||
};
|
||||
|
||||
*ret = n;
|
||||
@ -6093,6 +6127,7 @@ static int exec_runtime_add(
|
||||
char **tmp_dir,
|
||||
char **var_tmp_dir,
|
||||
int netns_storage_socket[2],
|
||||
int ipcns_storage_socket[2],
|
||||
ExecRuntime **ret) {
|
||||
|
||||
_cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
|
||||
@ -6101,7 +6136,7 @@ static int exec_runtime_add(
|
||||
assert(m);
|
||||
assert(id);
|
||||
|
||||
/* tmp_dir, var_tmp_dir, netns_storage_socket fds are donated on success */
|
||||
/* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
|
||||
|
||||
r = exec_runtime_allocate(&rt, id);
|
||||
if (r < 0)
|
||||
@ -6120,6 +6155,11 @@ static int exec_runtime_add(
|
||||
rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
|
||||
}
|
||||
|
||||
if (ipcns_storage_socket) {
|
||||
rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]);
|
||||
rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]);
|
||||
}
|
||||
|
||||
rt->manager = m;
|
||||
|
||||
if (ret)
|
||||
@ -6136,7 +6176,7 @@ static int exec_runtime_make(
|
||||
ExecRuntime **ret) {
|
||||
|
||||
_cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
|
||||
_cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 };
|
||||
_cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 }, ipcns_storage_socket[2] = { -1, -1 };
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@ -6144,7 +6184,7 @@ static int exec_runtime_make(
|
||||
assert(id);
|
||||
|
||||
/* It is not necessary to create ExecRuntime object. */
|
||||
if (!c->private_network && !c->private_tmp && !c->network_namespace_path) {
|
||||
if (!c->private_network && !c->private_ipc && !c->private_tmp && !c->network_namespace_path) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
@ -6163,7 +6203,12 @@ static int exec_runtime_make(
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ret);
|
||||
if (c->private_ipc || c->ipc_namespace_path) {
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -6254,6 +6299,26 @@ int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
|
||||
fprintf(f, " netns-socket-1=%i", copy);
|
||||
}
|
||||
|
||||
if (rt->ipcns_storage_socket[0] >= 0) {
|
||||
int copy;
|
||||
|
||||
copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]);
|
||||
if (copy < 0)
|
||||
return copy;
|
||||
|
||||
fprintf(f, " ipcns-socket-0=%i", copy);
|
||||
}
|
||||
|
||||
if (rt->ipcns_storage_socket[1] >= 0) {
|
||||
int copy;
|
||||
|
||||
copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]);
|
||||
if (copy < 0)
|
||||
return copy;
|
||||
|
||||
fprintf(f, " ipcns-socket-1=%i", copy);
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
@ -6335,6 +6400,28 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
|
||||
|
||||
safe_close(rt->netns_storage_socket[1]);
|
||||
rt->netns_storage_socket[1] = fdset_remove(fds, fd);
|
||||
|
||||
} else if (streq(key, "ipcns-socket-0")) {
|
||||
int fd;
|
||||
|
||||
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
|
||||
log_unit_debug(u, "Failed to parse ipcns socket value: %s", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
safe_close(rt->ipcns_storage_socket[0]);
|
||||
rt->ipcns_storage_socket[0] = fdset_remove(fds, fd);
|
||||
|
||||
} else if (streq(key, "ipcns-socket-1")) {
|
||||
int fd;
|
||||
|
||||
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
|
||||
log_unit_debug(u, "Failed to parse ipcns socket value: %s", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
safe_close(rt->ipcns_storage_socket[1]);
|
||||
rt->ipcns_storage_socket[1] = fdset_remove(fds, fd);
|
||||
} else
|
||||
return 0;
|
||||
|
||||
@ -6358,7 +6445,7 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
|
||||
int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
|
||||
_cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
|
||||
char *id = NULL;
|
||||
int r, fdpair[] = {-1, -1};
|
||||
int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
|
||||
const char *p, *v = value;
|
||||
size_t n;
|
||||
|
||||
@ -6401,13 +6488,13 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
|
||||
n = strcspn(v, " ");
|
||||
buf = strndupa(v, n);
|
||||
|
||||
r = safe_atoi(buf, &fdpair[0]);
|
||||
r = safe_atoi(buf, &netns_fdpair[0]);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-0=%s: %m", buf);
|
||||
if (!fdset_contains(fds, fdpair[0]))
|
||||
if (!fdset_contains(fds, netns_fdpair[0]))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
|
||||
"exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", fdpair[0]);
|
||||
fdpair[0] = fdset_remove(fds, fdpair[0]);
|
||||
"exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", netns_fdpair[0]);
|
||||
netns_fdpair[0] = fdset_remove(fds, netns_fdpair[0]);
|
||||
if (v[n] != ' ')
|
||||
goto finalize;
|
||||
p = v + n + 1;
|
||||
@ -6419,17 +6506,56 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
|
||||
|
||||
n = strcspn(v, " ");
|
||||
buf = strndupa(v, n);
|
||||
r = safe_atoi(buf, &fdpair[1]);
|
||||
|
||||
r = safe_atoi(buf, &netns_fdpair[1]);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-1=%s: %m", buf);
|
||||
if (!fdset_contains(fds, fdpair[1]))
|
||||
if (!fdset_contains(fds, netns_fdpair[1]))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
|
||||
"exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", fdpair[1]);
|
||||
fdpair[1] = fdset_remove(fds, fdpair[1]);
|
||||
"exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", netns_fdpair[1]);
|
||||
netns_fdpair[1] = fdset_remove(fds, netns_fdpair[1]);
|
||||
if (v[n] != ' ')
|
||||
goto finalize;
|
||||
p = v + n + 1;
|
||||
}
|
||||
|
||||
v = startswith(p, "ipcns-socket-0=");
|
||||
if (v) {
|
||||
char *buf;
|
||||
|
||||
n = strcspn(v, " ");
|
||||
buf = strndupa(v, n);
|
||||
|
||||
r = safe_atoi(buf, &ipcns_fdpair[0]);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Unable to parse exec-runtime specification ipcns-socket-0=%s: %m", buf);
|
||||
if (!fdset_contains(fds, ipcns_fdpair[0]))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
|
||||
"exec-runtime specification ipcns-socket-0= refers to unknown fd %d: %m", ipcns_fdpair[0]);
|
||||
ipcns_fdpair[0] = fdset_remove(fds, ipcns_fdpair[0]);
|
||||
if (v[n] != ' ')
|
||||
goto finalize;
|
||||
p = v + n + 1;
|
||||
}
|
||||
|
||||
v = startswith(p, "ipcns-socket-1=");
|
||||
if (v) {
|
||||
char *buf;
|
||||
|
||||
n = strcspn(v, " ");
|
||||
buf = strndupa(v, n);
|
||||
|
||||
r = safe_atoi(buf, &ipcns_fdpair[1]);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Unable to parse exec-runtime specification ipcns-socket-1=%s: %m", buf);
|
||||
if (!fdset_contains(fds, ipcns_fdpair[1]))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
|
||||
"exec-runtime specification ipcns-socket-1= refers to unknown fd %d: %m", ipcns_fdpair[1]);
|
||||
ipcns_fdpair[1] = fdset_remove(fds, ipcns_fdpair[1]);
|
||||
}
|
||||
|
||||
finalize:
|
||||
r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, fdpair, NULL);
|
||||
r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to add exec-runtime: %m");
|
||||
return 0;
|
||||
|
@ -117,6 +117,9 @@ struct ExecRuntime {
|
||||
/* An AF_UNIX socket pair, that contains a datagram containing a file descriptor referring to the network
|
||||
* namespace. */
|
||||
int netns_storage_socket[2];
|
||||
|
||||
/* Like netns_storage_socket, but the file descriptor is referring to the IPC namespace. */
|
||||
int ipcns_storage_socket[2];
|
||||
};
|
||||
|
||||
typedef enum ExecDirectoryType {
|
||||
@ -280,6 +283,7 @@ struct ExecContext {
|
||||
bool private_devices;
|
||||
bool private_users;
|
||||
bool private_mounts;
|
||||
bool private_ipc;
|
||||
bool protect_kernel_tunables;
|
||||
bool protect_kernel_modules;
|
||||
bool protect_kernel_logs;
|
||||
@ -314,6 +318,7 @@ struct ExecContext {
|
||||
Set *address_families;
|
||||
|
||||
char *network_namespace_path;
|
||||
char *ipc_namespace_path;
|
||||
|
||||
ExecDirectory directories[_EXEC_DIRECTORY_TYPE_MAX];
|
||||
ExecPreserveMode runtime_directory_preserve_mode;
|
||||
|
@ -133,10 +133,12 @@ $1.ProtectKernelLogs, config_parse_bool,
|
||||
$1.ProtectClock, config_parse_bool, 0, offsetof($1, exec_context.protect_clock)
|
||||
$1.ProtectControlGroups, config_parse_bool, 0, offsetof($1, exec_context.protect_control_groups)
|
||||
$1.NetworkNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.network_namespace_path)
|
||||
$1.IPCNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.ipc_namespace_path)
|
||||
$1.LogNamespace, config_parse_log_namespace, 0, offsetof($1, exec_context)
|
||||
$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network)
|
||||
$1.PrivateUsers, config_parse_bool, 0, offsetof($1, exec_context.private_users)
|
||||
$1.PrivateMounts, config_parse_bool, 0, offsetof($1, exec_context.private_mounts)
|
||||
$1.PrivateIPC, config_parse_bool, 0, offsetof($1, exec_context.private_ipc)
|
||||
$1.ProtectSystem, config_parse_protect_system, 0, offsetof($1, exec_context.protect_system)
|
||||
$1.ProtectHome, config_parse_protect_home, 0, offsetof($1, exec_context.protect_home)
|
||||
$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context.mount_flags)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "mountpoint-util.h"
|
||||
#include "namespace-util.h"
|
||||
#include "namespace.h"
|
||||
#include "nsflags.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "os-util.h"
|
||||
#include "path-util.h"
|
||||
@ -63,6 +64,7 @@ typedef enum MountMode {
|
||||
EXEC,
|
||||
TMPFS,
|
||||
EXTENSION_IMAGES, /* Mounted outside the root directory, and used by subsequent mounts */
|
||||
MQUEUEFS,
|
||||
READWRITE_IMPLICIT, /* Should have the lowest priority. */
|
||||
_MOUNT_MODE_MAX,
|
||||
} MountMode;
|
||||
@ -227,6 +229,7 @@ static const char * const mount_mode_table[_MOUNT_MODE_MAX] = {
|
||||
[READWRITE_IMPLICIT] = "rw-implicit",
|
||||
[EXEC] = "exec",
|
||||
[NOEXEC] = "noexec",
|
||||
[MQUEUEFS] = "mqueuefs",
|
||||
};
|
||||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(mount_mode, MountMode);
|
||||
@ -1112,6 +1115,24 @@ static int mount_run(const MountEntry *m) {
|
||||
return mount_tmpfs(m);
|
||||
}
|
||||
|
||||
static int mount_mqueuefs(const MountEntry *m) {
|
||||
int r;
|
||||
const char *entry_path;
|
||||
|
||||
assert(m);
|
||||
|
||||
entry_path = mount_entry_path(m);
|
||||
|
||||
(void) mkdir_p_label(entry_path, 0755);
|
||||
(void) umount_recursive(entry_path, 0);
|
||||
|
||||
r = mount_nofollow_verbose(LOG_DEBUG, "mqueue", entry_path, "mqueue", m->flags, mount_entry_options(m));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mount_image(const MountEntry *m, const char *root_directory) {
|
||||
|
||||
_cleanup_free_ char *host_os_release_id = NULL, *host_os_release_version_id = NULL,
|
||||
@ -1316,6 +1337,9 @@ static int apply_one_mount(
|
||||
case RUN:
|
||||
return mount_run(m);
|
||||
|
||||
case MQUEUEFS:
|
||||
return mount_mqueuefs(m);
|
||||
|
||||
case MOUNT_IMAGES:
|
||||
return mount_image(m, NULL);
|
||||
|
||||
@ -1515,7 +1539,8 @@ static size_t namespace_calculate_mounts(
|
||||
(creds_path ? 2 : 1) +
|
||||
!!log_namespace +
|
||||
setup_propagate + /* /run/systemd/incoming */
|
||||
!!notify_socket;
|
||||
!!notify_socket +
|
||||
ns_info->private_ipc; /* /dev/mqueue */
|
||||
}
|
||||
|
||||
static void normalize_mounts(const char *root_directory, MountEntry *mounts, size_t *n_mounts) {
|
||||
@ -2026,6 +2051,14 @@ int setup_namespace(
|
||||
};
|
||||
}
|
||||
|
||||
if (ns_info->private_ipc) {
|
||||
*(m++) = (MountEntry) {
|
||||
.path_const = "/dev/mqueue",
|
||||
.mode = MQUEUEFS,
|
||||
.flags = MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME,
|
||||
};
|
||||
}
|
||||
|
||||
if (creds_path) {
|
||||
/* If our service has a credentials store configured, then bind that one in, but hide
|
||||
* everything else. */
|
||||
@ -2508,13 +2541,17 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setup_netns(const int netns_storage_socket[static 2]) {
|
||||
_cleanup_close_ int netns = -1;
|
||||
int setup_shareable_ns(const int ns_storage_socket[static 2], unsigned long nsflag) {
|
||||
_cleanup_close_ int ns = -1;
|
||||
int r, q;
|
||||
const char *ns_name, *ns_path;
|
||||
|
||||
assert(netns_storage_socket);
|
||||
assert(netns_storage_socket[0] >= 0);
|
||||
assert(netns_storage_socket[1] >= 0);
|
||||
assert(ns_storage_socket);
|
||||
assert(ns_storage_socket[0] >= 0);
|
||||
assert(ns_storage_socket[1] >= 0);
|
||||
|
||||
ns_name = namespace_single_flag_to_string(nsflag);
|
||||
assert(ns_name);
|
||||
|
||||
/* We use the passed socketpair as a storage buffer for our
|
||||
* namespace reference fd. Whatever process runs this first
|
||||
@ -2524,35 +2561,36 @@ int setup_netns(const int netns_storage_socket[static 2]) {
|
||||
*
|
||||
* It's a bit crazy, but hey, works great! */
|
||||
|
||||
if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
|
||||
if (lockf(ns_storage_socket[0], F_LOCK, 0) < 0)
|
||||
return -errno;
|
||||
|
||||
netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
|
||||
if (netns == -EAGAIN) {
|
||||
ns = receive_one_fd(ns_storage_socket[0], MSG_DONTWAIT);
|
||||
if (ns == -EAGAIN) {
|
||||
/* Nothing stored yet, so let's create a new namespace. */
|
||||
|
||||
if (unshare(CLONE_NEWNET) < 0) {
|
||||
if (unshare(nsflag) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
(void) loopback_setup();
|
||||
|
||||
netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (netns < 0) {
|
||||
ns_path = strjoina("/proc/self/ns/", ns_name);
|
||||
ns = open(ns_path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (ns < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
} else if (netns < 0) {
|
||||
r = netns;
|
||||
} else if (ns < 0) {
|
||||
r = ns;
|
||||
goto fail;
|
||||
|
||||
} else {
|
||||
/* Yay, found something, so let's join the namespace */
|
||||
if (setns(netns, CLONE_NEWNET) < 0) {
|
||||
if (setns(ns, nsflag) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
@ -2560,45 +2598,45 @@ int setup_netns(const int netns_storage_socket[static 2]) {
|
||||
r = 0;
|
||||
}
|
||||
|
||||
q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
|
||||
q = send_one_fd(ns_storage_socket[1], ns, MSG_DONTWAIT);
|
||||
if (q < 0) {
|
||||
r = q;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
(void) lockf(netns_storage_socket[0], F_ULOCK, 0);
|
||||
(void) lockf(ns_storage_socket[0], F_ULOCK, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
int open_netns_path(const int netns_storage_socket[static 2], const char *path) {
|
||||
_cleanup_close_ int netns = -1;
|
||||
int open_shareable_ns_path(const int ns_storage_socket[static 2], const char *path, unsigned long nsflag) {
|
||||
_cleanup_close_ int ns = -1;
|
||||
int q, r;
|
||||
|
||||
assert(netns_storage_socket);
|
||||
assert(netns_storage_socket[0] >= 0);
|
||||
assert(netns_storage_socket[1] >= 0);
|
||||
assert(ns_storage_socket);
|
||||
assert(ns_storage_socket[0] >= 0);
|
||||
assert(ns_storage_socket[1] >= 0);
|
||||
assert(path);
|
||||
|
||||
/* If the storage socket doesn't contain a netns fd yet, open one via the file system and store it in
|
||||
* it. This is supposed to be called ahead of time, i.e. before setup_netns() which will allocate a
|
||||
* new anonymous netns if needed. */
|
||||
/* If the storage socket doesn't contain a ns fd yet, open one via the file system and store it in
|
||||
* it. This is supposed to be called ahead of time, i.e. before setup_shareable_ns() which will
|
||||
* allocate a new anonymous ns if needed. */
|
||||
|
||||
if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
|
||||
if (lockf(ns_storage_socket[0], F_LOCK, 0) < 0)
|
||||
return -errno;
|
||||
|
||||
netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
|
||||
if (netns == -EAGAIN) {
|
||||
ns = receive_one_fd(ns_storage_socket[0], MSG_DONTWAIT);
|
||||
if (ns == -EAGAIN) {
|
||||
/* Nothing stored yet. Open the file from the file system. */
|
||||
|
||||
netns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (netns < 0) {
|
||||
ns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (ns < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = fd_is_network_ns(netns);
|
||||
if (r == 0) { /* Not a netns? Refuse early. */
|
||||
r = fd_is_ns(ns, nsflag);
|
||||
if (r == 0) { /* Not a ns of our type? Refuse early. */
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
@ -2607,20 +2645,20 @@ int open_netns_path(const int netns_storage_socket[static 2], const char *path)
|
||||
|
||||
r = 1;
|
||||
|
||||
} else if (netns < 0) {
|
||||
r = netns;
|
||||
} else if (ns < 0) {
|
||||
r = ns;
|
||||
goto fail;
|
||||
} else
|
||||
r = 0; /* Already allocated */
|
||||
|
||||
q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
|
||||
q = send_one_fd(ns_storage_socket[1], ns, MSG_DONTWAIT);
|
||||
if (q < 0) {
|
||||
r = q;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
(void) lockf(netns_storage_socket[0], F_ULOCK, 0);
|
||||
(void) lockf(ns_storage_socket[0], F_ULOCK, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,7 @@ struct NamespaceInfo {
|
||||
bool protect_kernel_logs;
|
||||
bool mount_apivfs;
|
||||
bool protect_hostname;
|
||||
bool private_ipc;
|
||||
ProtectHome protect_home;
|
||||
ProtectSystem protect_system;
|
||||
ProtectProc protect_proc;
|
||||
@ -160,8 +161,8 @@ int setup_tmp_dirs(
|
||||
char **tmp_dir,
|
||||
char **var_tmp_dir);
|
||||
|
||||
int setup_netns(const int netns_storage_socket[static 2]);
|
||||
int open_netns_path(const int netns_storage_socket[static 2], const char *path);
|
||||
int setup_shareable_ns(const int ns_storage_socket[static 2], unsigned long nsflag);
|
||||
int open_shareable_ns_path(const int netns_storage_socket[static 2], const char *path, unsigned long nsflag);
|
||||
|
||||
const char* protect_home_to_string(ProtectHome p) _const_;
|
||||
ProtectHome protect_home_from_string(const char *s) _pure_;
|
||||
|
@ -1547,11 +1547,19 @@ static int socket_address_listen_in_cgroup(
|
||||
if (s->exec_context.network_namespace_path &&
|
||||
s->exec_runtime &&
|
||||
s->exec_runtime->netns_storage_socket[0] >= 0) {
|
||||
r = open_netns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path);
|
||||
r = open_shareable_ns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path, CLONE_NEWNET);
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(UNIT(s), r, "Failed to open network namespace path %s: %m", s->exec_context.network_namespace_path);
|
||||
}
|
||||
|
||||
if (s->exec_context.ipc_namespace_path &&
|
||||
s->exec_runtime &&
|
||||
s->exec_runtime->ipcns_storage_socket[0] >= 0) {
|
||||
r = open_shareable_ns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path, CLONE_NEWIPC);
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(UNIT(s), r, "Failed to open IPC namespace path %s: %m", s->exec_context.ipc_namespace_path);
|
||||
}
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
|
||||
return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
|
||||
|
||||
@ -1568,7 +1576,7 @@ static int socket_address_listen_in_cgroup(
|
||||
s->exec_runtime->netns_storage_socket[0] >= 0) {
|
||||
|
||||
if (ns_type_supported(NAMESPACE_NET)) {
|
||||
r = setup_netns(s->exec_runtime->netns_storage_socket);
|
||||
r = setup_shareable_ns(s->exec_runtime->netns_storage_socket, CLONE_NEWNET);
|
||||
if (r < 0) {
|
||||
log_unit_error_errno(UNIT(s), r, "Failed to join network namespace: %m");
|
||||
_exit(EXIT_NETWORK);
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <fnmatch.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/fs.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@ -2095,8 +2094,6 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
|
||||
{ .fd = poll_fd, .events = POLLIN },
|
||||
{ .fd = STDOUT_FILENO },
|
||||
};
|
||||
|
||||
struct timespec ts;
|
||||
usec_t timeout;
|
||||
int r;
|
||||
|
||||
@ -2110,21 +2107,16 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine journal waiting time: %m");
|
||||
|
||||
if (ppoll(pollfds, ELEMENTSOF(pollfds),
|
||||
timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0) {
|
||||
if (errno == EINTR)
|
||||
r = ppoll_usec(pollfds, ELEMENTSOF(pollfds), timeout);
|
||||
if (r == -EINTR)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Couldn't wait for journal event: %m");
|
||||
|
||||
return log_error_errno(errno, "Couldn't wait for journal event: %m");
|
||||
}
|
||||
|
||||
if (pollfds[1].revents & (POLLHUP|POLLERR|POLLNVAL)) /* STDOUT has been closed? */
|
||||
if (pollfds[1].revents & (POLLHUP|POLLERR)) /* STDOUT has been closed? */
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED),
|
||||
"Standard output has been closed.");
|
||||
|
||||
if (pollfds[0].revents & POLLNVAL)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADF), "Change fd closed?");
|
||||
|
||||
r = sd_journal_process(j);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to process journal events: %m");
|
||||
|
@ -869,7 +869,7 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
|
||||
}
|
||||
|
||||
int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
|
||||
_cleanup_free_ char *temp_path = NULL;
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
struct sd_dhcp_raw_option *option;
|
||||
struct in_addr address;
|
||||
@ -889,7 +889,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
|
||||
|
||||
r = fopen_temporary(lease_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
(void) fchmod(fileno(f), 0644);
|
||||
|
||||
@ -992,10 +992,8 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
|
||||
_cleanup_free_ char *client_id_hex = NULL;
|
||||
|
||||
client_id_hex = hexmem(client_id, client_id_len);
|
||||
if (!client_id_hex) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (!client_id_hex)
|
||||
return -ENOMEM;
|
||||
fprintf(f, "CLIENTID=%s\n", client_id_hex);
|
||||
}
|
||||
|
||||
@ -1004,10 +1002,8 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
|
||||
_cleanup_free_ char *option_hex = NULL;
|
||||
|
||||
option_hex = hexmem(data, data_len);
|
||||
if (!option_hex) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (!option_hex)
|
||||
return -ENOMEM;
|
||||
fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
|
||||
}
|
||||
|
||||
@ -1017,28 +1013,23 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
|
||||
xsprintf(key, "OPTION_%" PRIu8, option->tag);
|
||||
r = serialize_dhcp_option(f, key, option->data, option->length);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
}
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
r = conservative_rename(temp_path, lease_file);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
temp_path = mfree(temp_path);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (temp_path)
|
||||
(void) unlink(temp_path);
|
||||
|
||||
return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
|
||||
}
|
||||
|
||||
int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
|
||||
|
||||
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
|
||||
_cleanup_free_ char
|
||||
*address = NULL,
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <endian.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
@ -32,6 +31,7 @@
|
||||
#include "fd-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "hostname-util.h"
|
||||
#include "io-util.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "missing_syscall.h"
|
||||
@ -3255,9 +3255,8 @@ _public_ int sd_bus_process_priority(sd_bus *bus, int64_t priority, sd_bus_messa
|
||||
|
||||
static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
|
||||
struct pollfd p[2] = {};
|
||||
int r, n;
|
||||
struct timespec ts;
|
||||
usec_t m = USEC_INFINITY;
|
||||
int r, n;
|
||||
|
||||
assert(bus);
|
||||
|
||||
@ -3312,16 +3311,9 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
|
||||
if (timeout_usec != (uint64_t) -1 && (m == USEC_INFINITY || timeout_usec < m))
|
||||
m = timeout_usec;
|
||||
|
||||
r = ppoll(p, n, m == USEC_INFINITY ? NULL : timespec_store(&ts, m), NULL);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
if (p[0].revents & POLLNVAL)
|
||||
return -EBADF;
|
||||
if (n >= 2 && (p[1].revents & POLLNVAL))
|
||||
return -EBADF;
|
||||
r = ppoll_usec(p, n, m);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -206,12 +206,10 @@ static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_
|
||||
for (;;) {
|
||||
/* Wait for next message */
|
||||
r = fd_wait_for_event(device_monitor_get_fd(udev_monitor->monitor), POLLIN, 0);
|
||||
if (r < 0) {
|
||||
if (IN_SET(r, -EINTR, -EAGAIN))
|
||||
if (r == -EINTR)
|
||||
continue;
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (r == 0)
|
||||
return -EAGAIN;
|
||||
|
||||
|
@ -113,6 +113,8 @@ sources = files('''
|
||||
networkd-speed-meter.h
|
||||
networkd-sriov.c
|
||||
networkd-sriov.h
|
||||
networkd-state-file.c
|
||||
networkd-state-file.h
|
||||
networkd-sysctl.c
|
||||
networkd-sysctl.h
|
||||
networkd-util.c
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "string-table.h"
|
||||
#include "strv.h"
|
||||
#include "sysctl-util.h"
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "networkd-link-bus.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "parse-util.h"
|
||||
#include "resolve-util.h"
|
||||
#include "socket-netlink.h"
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "bond.h"
|
||||
#include "bridge.h"
|
||||
#include "bus-util.h"
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "env-file.h"
|
||||
@ -42,6 +44,7 @@
|
||||
#include "networkd-sysctl.h"
|
||||
#include "networkd-radv.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "networkd-wifi.h"
|
||||
#include "set.h"
|
||||
#include "socket-util.h"
|
||||
@ -543,8 +546,6 @@ static Link *link_free(Link *link) {
|
||||
link->ndisc_addresses = set_free(link->ndisc_addresses);
|
||||
|
||||
link_free_engines(link);
|
||||
free(link->lease_file);
|
||||
free(link->lldp_file);
|
||||
|
||||
free(link->ifname);
|
||||
strv_free(link->alternative_names);
|
||||
@ -552,8 +553,9 @@ static Link *link_free(Link *link) {
|
||||
free(link->ssid);
|
||||
free(link->driver);
|
||||
|
||||
(void) unlink(link->state_file);
|
||||
free(link->state_file);
|
||||
unlink_and_free(link->lease_file);
|
||||
unlink_and_free(link->lldp_file);
|
||||
unlink_and_free(link->state_file);
|
||||
|
||||
sd_device_unref(link->sd_device);
|
||||
|
||||
@ -1733,7 +1735,7 @@ static void link_detach_from_manager(Link *link) {
|
||||
link_unref(link);
|
||||
}
|
||||
|
||||
void link_drop(Link *link) {
|
||||
static void link_drop(Link *link) {
|
||||
if (!link || link->state == LINK_STATE_LINGER)
|
||||
return;
|
||||
|
||||
@ -2380,7 +2382,7 @@ static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin
|
||||
return 1;
|
||||
}
|
||||
|
||||
int link_initialized(Link *link, sd_device *device) {
|
||||
static int link_initialized(Link *link, sd_device *device) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
|
||||
@ -2420,7 +2422,7 @@ int link_initialized(Link *link, sd_device *device) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
|
||||
static int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
||||
char ifindex_str[2 + DECIMAL_STR_MAX(int)];
|
||||
Link *link;
|
||||
@ -2505,6 +2507,57 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) {
|
||||
sd_device_action_t action;
|
||||
Manager *m = userdata;
|
||||
Link *link = NULL;
|
||||
int r, ifindex;
|
||||
|
||||
assert(m);
|
||||
assert(device);
|
||||
|
||||
r = sd_device_get_action(device, &action);
|
||||
if (r < 0) {
|
||||
log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ignore the "remove" uevent — let's remove a device only if rtnetlink says so. All other uevents
|
||||
* are "positive" events in some form, i.e. inform us about a changed or new network interface, that
|
||||
* still exists — and we are interested in that. */
|
||||
if (action == SD_DEVICE_REMOVE)
|
||||
return 0;
|
||||
|
||||
r = sd_device_get_ifindex(device, &ifindex);
|
||||
if (r < 0) {
|
||||
log_device_debug_errno(device, r, "Ignoring udev %s event for device without ifindex or with invalid ifindex: %m",
|
||||
device_action_to_string(action));
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = device_is_renaming(device);
|
||||
if (r < 0) {
|
||||
log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m",
|
||||
device_action_to_string(action));
|
||||
return 0;
|
||||
}
|
||||
if (r > 0) {
|
||||
log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_get(m, ifindex, &link);
|
||||
if (r < 0) {
|
||||
if (r != -ENODEV)
|
||||
log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) link_initialized(link, device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_carrier_gained(Link *link) {
|
||||
int r;
|
||||
|
||||
@ -2618,13 +2671,14 @@ int link_carrier_reset(Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is called every time an interface admin state changes to up;
|
||||
* specifically, when IFF_UP flag changes from unset to set */
|
||||
static int link_admin_state_up(Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
/* This is called every time an interface admin state changes to up;
|
||||
* specifically, when IFF_UP flag changes from unset to set. */
|
||||
|
||||
if (!link->network)
|
||||
return 0;
|
||||
|
||||
@ -2648,7 +2702,6 @@ static int link_admin_state_up(Link *link) {
|
||||
}
|
||||
|
||||
static int link_admin_state_down(Link *link) {
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!link->network)
|
||||
@ -2662,7 +2715,7 @@ static int link_admin_state_down(Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_update(Link *link, sd_netlink_message *m) {
|
||||
static int link_update(Link *link, sd_netlink_message *m) {
|
||||
_cleanup_strv_free_ char **s = NULL;
|
||||
hw_addr_data hw_addr;
|
||||
const char *ifname;
|
||||
@ -2806,390 +2859,93 @@ int link_update(Link *link, sd_netlink_message *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
|
||||
bool space = false;
|
||||
Link *link;
|
||||
int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
|
||||
Link *link = NULL;
|
||||
NetDev *netdev = NULL;
|
||||
uint16_t type;
|
||||
const char *name;
|
||||
int r, ifindex;
|
||||
|
||||
assert(f);
|
||||
assert(prefix);
|
||||
assert(rtnl);
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
if (hashmap_isempty(h))
|
||||
return;
|
||||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring");
|
||||
|
||||
fputs(prefix, f);
|
||||
HASHMAP_FOREACH(link, h) {
|
||||
if (space)
|
||||
fputc(' ', f);
|
||||
|
||||
fprintf(f, "%i", link->ifindex);
|
||||
space = true;
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
|
||||
for (unsigned j = 0; j < n_dns; j++) {
|
||||
const char *str;
|
||||
|
||||
if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
|
||||
continue;
|
||||
|
||||
str = in_addr_full_to_string(dns[j]);
|
||||
if (!str)
|
||||
continue;
|
||||
|
||||
if (*space)
|
||||
fputc(' ', f);
|
||||
fputs(str, f);
|
||||
*space = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void serialize_addresses(
|
||||
FILE *f,
|
||||
const char *lvalue,
|
||||
bool *space,
|
||||
char **addresses,
|
||||
sd_dhcp_lease *lease,
|
||||
bool conditional,
|
||||
sd_dhcp_lease_server_type_t what,
|
||||
sd_dhcp6_lease *lease6,
|
||||
bool conditional6,
|
||||
int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**),
|
||||
int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) {
|
||||
int r;
|
||||
|
||||
bool _space = false;
|
||||
if (!space)
|
||||
space = &_space;
|
||||
|
||||
if (lvalue)
|
||||
fprintf(f, "%s=", lvalue);
|
||||
fputstrv(f, addresses, NULL, space);
|
||||
|
||||
if (lease && conditional) {
|
||||
const struct in_addr *lease_addresses;
|
||||
|
||||
r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses);
|
||||
if (r > 0)
|
||||
serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local);
|
||||
}
|
||||
|
||||
if (lease6 && conditional6 && lease6_get_addr) {
|
||||
const struct in6_addr *in6_addrs;
|
||||
|
||||
r = lease6_get_addr(lease6, &in6_addrs);
|
||||
if (r > 0)
|
||||
serialize_in6_addrs(f, in6_addrs, r, space);
|
||||
}
|
||||
|
||||
if (lease6 && conditional6 && lease6_get_fqdn) {
|
||||
char **in6_hosts;
|
||||
|
||||
r = lease6_get_fqdn(lease6, &in6_hosts);
|
||||
if (r > 0)
|
||||
fputstrv(f, in6_hosts, NULL, space);
|
||||
}
|
||||
|
||||
if (lvalue)
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
int link_save(Link *link) {
|
||||
const char *admin_state, *oper_state, *carrier_state, *address_state;
|
||||
_cleanup_free_ char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->state_file);
|
||||
assert(link->lease_file);
|
||||
assert(link->manager);
|
||||
|
||||
if (link->state == LINK_STATE_LINGER) {
|
||||
(void) unlink(link->state_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
link_lldp_save(link);
|
||||
|
||||
admin_state = link_state_to_string(link->state);
|
||||
assert(admin_state);
|
||||
|
||||
oper_state = link_operstate_to_string(link->operstate);
|
||||
assert(oper_state);
|
||||
|
||||
carrier_state = link_carrier_state_to_string(link->carrier_state);
|
||||
assert(carrier_state);
|
||||
|
||||
address_state = link_address_state_to_string(link->address_state);
|
||||
assert(address_state);
|
||||
|
||||
r = fopen_temporary(link->state_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
(void) fchmod(fileno(f), 0644);
|
||||
|
||||
fprintf(f,
|
||||
"# This is private data. Do not parse.\n"
|
||||
"ADMIN_STATE=%s\n"
|
||||
"OPER_STATE=%s\n"
|
||||
"CARRIER_STATE=%s\n"
|
||||
"ADDRESS_STATE=%s\n",
|
||||
admin_state, oper_state, carrier_state, address_state);
|
||||
|
||||
if (link->network) {
|
||||
char **dhcp6_domains = NULL, **dhcp_domains = NULL;
|
||||
const char *dhcp_domainname = NULL, *p;
|
||||
bool space;
|
||||
|
||||
fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
|
||||
yes_no(link->network->required_for_online));
|
||||
|
||||
LinkOperationalStateRange st = link->network->required_operstate_for_online;
|
||||
fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s%s%s\n",
|
||||
strempty(link_operstate_to_string(st.min)),
|
||||
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
|
||||
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
|
||||
|
||||
fprintf(f, "ACTIVATION_POLICY=%s\n",
|
||||
activation_policy_to_string(link->network->activation_policy));
|
||||
|
||||
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
fputs("DNS=", f);
|
||||
space = false;
|
||||
if (link->n_dns != (unsigned) -1)
|
||||
link_save_dns(link, f, link->dns, link->n_dns, &space);
|
||||
else
|
||||
link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
|
||||
|
||||
serialize_addresses(f, NULL, &space,
|
||||
NULL,
|
||||
link->dhcp_lease,
|
||||
link->network->dhcp_use_dns,
|
||||
SD_DHCP_LEASE_DNS,
|
||||
link->dhcp6_lease,
|
||||
link->network->dhcp6_use_dns,
|
||||
sd_dhcp6_lease_get_dns,
|
||||
NULL);
|
||||
|
||||
/* Make sure to flush out old entries before we use the NDisc data */
|
||||
ndisc_vacuum(link);
|
||||
|
||||
if (link->network->ipv6_accept_ra_use_dns && link->ndisc_rdnss) {
|
||||
NDiscRDNSS *dd;
|
||||
|
||||
SET_FOREACH(dd, link->ndisc_rdnss)
|
||||
serialize_in6_addrs(f, &dd->address, 1, &space);
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
serialize_addresses(f, "NTP", NULL,
|
||||
link->ntp ?: link->network->ntp,
|
||||
link->dhcp_lease,
|
||||
link->network->dhcp_use_ntp,
|
||||
SD_DHCP_LEASE_NTP,
|
||||
link->dhcp6_lease,
|
||||
link->network->dhcp6_use_ntp,
|
||||
sd_dhcp6_lease_get_ntp_addrs,
|
||||
sd_dhcp6_lease_get_ntp_fqdn);
|
||||
|
||||
serialize_addresses(f, "SIP", NULL,
|
||||
NULL,
|
||||
link->dhcp_lease,
|
||||
link->network->dhcp_use_sip,
|
||||
SD_DHCP_LEASE_SIP,
|
||||
NULL, false, NULL, NULL);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
|
||||
if (link->dhcp_lease) {
|
||||
(void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
|
||||
(void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains);
|
||||
}
|
||||
if (link->dhcp6_lease)
|
||||
(void) sd_dhcp6_lease_get_domains(link->dhcp6_lease, &dhcp6_domains);
|
||||
}
|
||||
|
||||
fputs("DOMAINS=", f);
|
||||
space = false;
|
||||
ORDERED_SET_FOREACH(p, link->search_domains ?: link->network->search_domains)
|
||||
fputs_with_space(f, p, NULL, &space);
|
||||
|
||||
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
|
||||
if (dhcp_domainname)
|
||||
fputs_with_space(f, dhcp_domainname, NULL, &space);
|
||||
if (dhcp_domains)
|
||||
fputstrv(f, dhcp_domains, NULL, &space);
|
||||
if (dhcp6_domains)
|
||||
fputstrv(f, dhcp6_domains, NULL, &space);
|
||||
}
|
||||
|
||||
if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_YES) {
|
||||
NDiscDNSSL *dd;
|
||||
|
||||
SET_FOREACH(dd, link->ndisc_dnssl)
|
||||
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
fputs("ROUTE_DOMAINS=", f);
|
||||
space = false;
|
||||
ORDERED_SET_FOREACH(p, link->route_domains ?: link->network->route_domains)
|
||||
fputs_with_space(f, p, NULL, &space);
|
||||
|
||||
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
|
||||
if (dhcp_domainname)
|
||||
fputs_with_space(f, dhcp_domainname, NULL, &space);
|
||||
if (dhcp_domains)
|
||||
fputstrv(f, dhcp_domains, NULL, &space);
|
||||
if (dhcp6_domains)
|
||||
fputstrv(f, dhcp6_domains, NULL, &space);
|
||||
}
|
||||
|
||||
if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_ROUTE) {
|
||||
NDiscDNSSL *dd;
|
||||
|
||||
SET_FOREACH(dd, link->ndisc_dnssl)
|
||||
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
fprintf(f, "LLMNR=%s\n",
|
||||
resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr));
|
||||
|
||||
/************************************************************/
|
||||
|
||||
fprintf(f, "MDNS=%s\n",
|
||||
resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns));
|
||||
|
||||
/************************************************************/
|
||||
|
||||
int dns_default_route =
|
||||
link->dns_default_route >= 0 ? link->dns_default_route :
|
||||
link->network->dns_default_route;
|
||||
if (dns_default_route >= 0)
|
||||
fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route));
|
||||
|
||||
/************************************************************/
|
||||
|
||||
DnsOverTlsMode dns_over_tls_mode =
|
||||
link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode :
|
||||
link->network->dns_over_tls_mode;
|
||||
if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
|
||||
fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode));
|
||||
|
||||
/************************************************************/
|
||||
|
||||
DnssecMode dnssec_mode =
|
||||
link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode :
|
||||
link->network->dnssec_mode;
|
||||
if (dnssec_mode != _DNSSEC_MODE_INVALID)
|
||||
fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode));
|
||||
|
||||
/************************************************************/
|
||||
|
||||
Set *nta_anchors = link->dnssec_negative_trust_anchors;
|
||||
if (set_isempty(nta_anchors))
|
||||
nta_anchors = link->network->dnssec_negative_trust_anchors;
|
||||
|
||||
if (!set_isempty(nta_anchors)) {
|
||||
const char *n;
|
||||
|
||||
fputs("DNSSEC_NTA=", f);
|
||||
space = false;
|
||||
SET_FOREACH(n, nta_anchors)
|
||||
fputs_with_space(f, n, NULL, &space);
|
||||
fputc('\n', f);
|
||||
}
|
||||
}
|
||||
|
||||
print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
|
||||
print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
|
||||
|
||||
if (link->dhcp_lease) {
|
||||
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
fprintf(f,
|
||||
"DHCP_LEASE=%s\n",
|
||||
link->lease_file);
|
||||
} else
|
||||
(void) unlink(link->lease_file);
|
||||
|
||||
r = link_serialize_dhcp6_client(link, f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = conservative_rename(temp_path, link->state_file);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_netlink_message_get_type(message, &type);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
(void) unlink(link->state_file);
|
||||
if (temp_path)
|
||||
(void) unlink(temp_path);
|
||||
|
||||
return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file);
|
||||
}
|
||||
|
||||
/* The serialized state in /run is no longer up-to-date. */
|
||||
void link_dirty(Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
/* mark manager dirty as link is dirty */
|
||||
manager_dirty(link->manager);
|
||||
|
||||
r = set_ensure_put(&link->manager->dirty_links, NULL, link);
|
||||
if (r <= 0)
|
||||
/* Ignore allocation errors and don't take another ref if the link was already dirty */
|
||||
return;
|
||||
link_ref(link);
|
||||
}
|
||||
|
||||
/* The serialized state in /run is up-to-date */
|
||||
void link_clean(Link *link) {
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
link_unref(set_remove(link->manager->dirty_links, link));
|
||||
}
|
||||
|
||||
int link_save_and_clean(Link *link) {
|
||||
int r;
|
||||
|
||||
r = link_save(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
link_clean(link);
|
||||
} else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
|
||||
log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m");
|
||||
return 0;
|
||||
} else if (ifindex <= 0) {
|
||||
log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) link_get(m, ifindex, &link);
|
||||
(void) netdev_get(m, name, &netdev);
|
||||
|
||||
switch (type) {
|
||||
case RTM_NEWLINK:
|
||||
if (!link) {
|
||||
/* link is new, so add it */
|
||||
r = link_add(m, message, &link);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not process new link message, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (netdev) {
|
||||
/* netdev exists, so make sure the ifindex matches */
|
||||
r = netdev_set_ifindex(netdev, message);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = link_update(link, message);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not process link message, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTM_DELLINK:
|
||||
link_drop(link);
|
||||
netdev_drop(netdev);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Received link message with invalid RTNL message type.");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char* const link_state_table[_LINK_STATE_MAX] = {
|
||||
[LINK_STATE_PENDING] = "pending",
|
||||
[LINK_STATE_INITIALIZED] = "initialized",
|
||||
|
@ -203,24 +203,15 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
|
||||
DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_destroy_callback, Link, link_unref);
|
||||
|
||||
int link_get(Manager *m, int ifindex, Link **ret);
|
||||
int link_add(Manager *manager, sd_netlink_message *message, Link **ret);
|
||||
void link_drop(Link *link);
|
||||
|
||||
int link_down(Link *link, link_netlink_message_handler_t callback);
|
||||
|
||||
void link_enter_failed(Link *link);
|
||||
int link_initialized(Link *link, sd_device *device);
|
||||
|
||||
void link_set_state(Link *link, LinkState state);
|
||||
void link_check_ready(Link *link);
|
||||
|
||||
void link_update_operstate(Link *link, bool also_update_bond_master);
|
||||
int link_update(Link *link, sd_netlink_message *message);
|
||||
|
||||
void link_dirty(Link *link);
|
||||
void link_clean(Link *link);
|
||||
int link_save(Link *link);
|
||||
int link_save_and_clean(Link *link);
|
||||
|
||||
int link_carrier_reset(Link *link);
|
||||
bool link_has_carrier(Link *link);
|
||||
@ -241,6 +232,9 @@ LinkState link_state_from_string(const char *s) _pure_;
|
||||
int link_configure(Link *link);
|
||||
int link_reconfigure(Link *link, bool force);
|
||||
|
||||
int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata);
|
||||
int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
|
||||
|
||||
int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg);
|
||||
#define log_link_message_error_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_ERR, err, msg)
|
||||
#define log_link_message_warning_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_WARNING, err, msg)
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-lldp-rx.h"
|
||||
#include "networkd-lldp-tx.h"
|
||||
@ -134,7 +135,7 @@ int link_update_lldp(Link *link) {
|
||||
}
|
||||
|
||||
int link_lldp_save(Link *link) {
|
||||
_cleanup_free_ char *temp_path = NULL;
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
sd_lldp_neighbor **l = NULL;
|
||||
int n = 0, r, i;
|
||||
@ -149,10 +150,10 @@ int link_lldp_save(Link *link) {
|
||||
|
||||
r = sd_lldp_get_neighbors(link->lldp, &l);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
return r;
|
||||
if (r == 0) {
|
||||
(void) unlink(link->lldp_file);
|
||||
goto finish;
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = r;
|
||||
@ -181,19 +182,13 @@ int link_lldp_save(Link *link) {
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (rename(temp_path, link->lldp_file) < 0) {
|
||||
r = -errno;
|
||||
r = conservative_rename(temp_path, link->lldp_file);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
finish:
|
||||
if (r < 0) {
|
||||
(void) unlink(link->lldp_file);
|
||||
if (temp_path)
|
||||
(void) unlink(temp_path);
|
||||
|
||||
if (r < 0)
|
||||
log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file);
|
||||
}
|
||||
|
||||
if (l) {
|
||||
for (i = 0; i < n; i++)
|
||||
|
@ -17,8 +17,6 @@
|
||||
#include "bus-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "def.h"
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "dns-domain.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@ -38,6 +36,7 @@
|
||||
#include "networkd-nexthop.h"
|
||||
#include "networkd-routing-policy-rule.h"
|
||||
#include "networkd-speed-meter.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "ordered-set.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
@ -48,7 +47,6 @@
|
||||
#include "strv.h"
|
||||
#include "sysctl-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "udev-util.h"
|
||||
|
||||
/* use 128 MB for receive socket kernel queue. */
|
||||
#define RCVBUF_SIZE (128*1024*1024)
|
||||
@ -181,57 +179,6 @@ int manager_connect_bus(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) {
|
||||
sd_device_action_t action;
|
||||
Manager *m = userdata;
|
||||
Link *link = NULL;
|
||||
int r, ifindex;
|
||||
|
||||
assert(m);
|
||||
assert(device);
|
||||
|
||||
r = sd_device_get_action(device, &action);
|
||||
if (r < 0) {
|
||||
log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ignore the "remove" uevent — let's remove a device only if rtnetlink says so. All other uevents
|
||||
* are "positive" events in some form, i.e. inform us about a changed or new network interface, that
|
||||
* still exists — and we are interested in that. */
|
||||
if (action == SD_DEVICE_REMOVE)
|
||||
return 0;
|
||||
|
||||
r = sd_device_get_ifindex(device, &ifindex);
|
||||
if (r < 0) {
|
||||
log_device_debug_errno(device, r, "Ignoring udev %s event for device without ifindex or with invalid ifindex: %m",
|
||||
device_action_to_string(action));
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = device_is_renaming(device);
|
||||
if (r < 0) {
|
||||
log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m",
|
||||
device_action_to_string(action));
|
||||
return 0;
|
||||
}
|
||||
if (r > 0) {
|
||||
log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_get(m, ifindex, &link);
|
||||
if (r < 0) {
|
||||
if (r != -ENODEV)
|
||||
log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) link_initialized(link, device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_connect_udev(Manager *m) {
|
||||
int r;
|
||||
|
||||
@ -263,93 +210,6 @@ static int manager_connect_udev(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
|
||||
Link *link = NULL;
|
||||
NetDev *netdev = NULL;
|
||||
uint16_t type;
|
||||
const char *name;
|
||||
int r, ifindex;
|
||||
|
||||
assert(rtnl);
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_get_type(message, &type);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
|
||||
return 0;
|
||||
} else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
|
||||
log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m");
|
||||
return 0;
|
||||
} else if (ifindex <= 0) {
|
||||
log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) link_get(m, ifindex, &link);
|
||||
(void) netdev_get(m, name, &netdev);
|
||||
|
||||
switch (type) {
|
||||
case RTM_NEWLINK:
|
||||
if (!link) {
|
||||
/* link is new, so add it */
|
||||
r = link_add(m, message, &link);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not process new link message, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (netdev) {
|
||||
/* netdev exists, so make sure the ifindex matches */
|
||||
r = netdev_set_ifindex(netdev, message);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = link_update(link, message);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Could not process link message, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTM_DELLINK:
|
||||
link_drop(link);
|
||||
netdev_drop(netdev);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Received link message with invalid RTNL message type.");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int systemd_netlink_fd(void) {
|
||||
int n, fd, rtnl_fd = -EINVAL;
|
||||
|
||||
@ -357,14 +217,13 @@ static int systemd_netlink_fd(void) {
|
||||
if (n <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
|
||||
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
|
||||
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
|
||||
if (rtnl_fd >= 0)
|
||||
return -EINVAL;
|
||||
|
||||
rtnl_fd = fd;
|
||||
}
|
||||
}
|
||||
|
||||
return rtnl_fd;
|
||||
}
|
||||
@ -466,300 +325,24 @@ static int manager_connect_rtnl(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) {
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(dns);
|
||||
|
||||
if (dns->ifindex != 0 && dns->ifindex != ifindex)
|
||||
return 0;
|
||||
|
||||
p = in_addr_full_to_string(dns);
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
r = ordered_set_put_strdup(s, p);
|
||||
if (r == -EEXIST)
|
||||
return 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) {
|
||||
int r, c = 0;
|
||||
|
||||
assert(s);
|
||||
assert(dns || n == 0);
|
||||
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
r = ordered_set_put_dns_server(s, ifindex, dns[i]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
c += r;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) {
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(address);
|
||||
|
||||
r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_set_consume(s, p);
|
||||
if (r == -EEXIST)
|
||||
return 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ordered_set_put_in4_addrv(OrderedSet *s,
|
||||
const struct in_addr *addresses,
|
||||
size_t n,
|
||||
bool (*predicate)(const struct in_addr *addr)) {
|
||||
int r, c = 0;
|
||||
|
||||
assert(s);
|
||||
assert(n == 0 || addresses);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (predicate && !predicate(&addresses[i]))
|
||||
continue;
|
||||
r = ordered_set_put_in4_addr(s, addresses+i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
c += r;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int manager_save(Manager *m) {
|
||||
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
|
||||
const char *operstate_str, *carrier_state_str, *address_state_str;
|
||||
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
|
||||
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
|
||||
LinkAddressState address_state = LINK_ADDRESS_STATE_OFF;
|
||||
_cleanup_free_ char *temp_path = NULL;
|
||||
_cleanup_strv_free_ char **p = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(m->state_file);
|
||||
|
||||
/* We add all NTP and DNS server to a set, to filter out duplicates */
|
||||
dns = ordered_set_new(&string_hash_ops);
|
||||
if (!dns)
|
||||
return -ENOMEM;
|
||||
|
||||
ntp = ordered_set_new(&string_hash_ops);
|
||||
if (!ntp)
|
||||
return -ENOMEM;
|
||||
|
||||
sip = ordered_set_new(&string_hash_ops);
|
||||
if (!sip)
|
||||
return -ENOMEM;
|
||||
|
||||
search_domains = ordered_set_new(&dns_name_hash_ops);
|
||||
if (!search_domains)
|
||||
return -ENOMEM;
|
||||
|
||||
route_domains = ordered_set_new(&dns_name_hash_ops);
|
||||
if (!route_domains)
|
||||
return -ENOMEM;
|
||||
|
||||
HASHMAP_FOREACH(link, m->links) {
|
||||
const struct in_addr *addresses;
|
||||
|
||||
if (link->flags & IFF_LOOPBACK)
|
||||
continue;
|
||||
|
||||
if (link->operstate > operstate)
|
||||
operstate = link->operstate;
|
||||
|
||||
if (link->carrier_state > carrier_state)
|
||||
carrier_state = link->carrier_state;
|
||||
|
||||
if (link->address_state > address_state)
|
||||
address_state = link->address_state;
|
||||
|
||||
if (!link->network)
|
||||
continue;
|
||||
|
||||
/* First add the static configured entries */
|
||||
if (link->n_dns != (unsigned) -1)
|
||||
r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns);
|
||||
else
|
||||
r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!link->dhcp_lease)
|
||||
continue;
|
||||
|
||||
/* Secondly, add the entries acquired via DHCP */
|
||||
if (link->network->dhcp_use_dns) {
|
||||
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
|
||||
if (r > 0) {
|
||||
r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_ntp) {
|
||||
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
|
||||
if (r > 0) {
|
||||
r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_sip) {
|
||||
r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
|
||||
if (r > 0) {
|
||||
r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
|
||||
const char *domainname;
|
||||
char **domains = NULL;
|
||||
|
||||
OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains;
|
||||
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
|
||||
if (r >= 0) {
|
||||
r = ordered_set_put_strdup(target_domains, domainname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r != -ENODATA)
|
||||
return r;
|
||||
|
||||
r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
|
||||
if (r >= 0) {
|
||||
r = ordered_set_put_strdupv(target_domains, domains);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
|
||||
carrier_state = LINK_CARRIER_STATE_CARRIER;
|
||||
|
||||
operstate_str = link_operstate_to_string(operstate);
|
||||
assert(operstate_str);
|
||||
|
||||
carrier_state_str = link_carrier_state_to_string(carrier_state);
|
||||
assert(carrier_state_str);
|
||||
|
||||
address_state_str = link_address_state_to_string(address_state);
|
||||
assert(address_state_str);
|
||||
|
||||
r = fopen_temporary(m->state_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) fchmod(fileno(f), 0644);
|
||||
|
||||
fprintf(f,
|
||||
"# This is private data. Do not parse.\n"
|
||||
"OPER_STATE=%s\n"
|
||||
"CARRIER_STATE=%s\n"
|
||||
"ADDRESS_STATE=%s\n",
|
||||
operstate_str, carrier_state_str, address_state_str);
|
||||
|
||||
ordered_set_print(f, "DNS=", dns);
|
||||
ordered_set_print(f, "NTP=", ntp);
|
||||
ordered_set_print(f, "SIP=", sip);
|
||||
ordered_set_print(f, "DOMAINS=", search_domains);
|
||||
ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = conservative_rename(temp_path, m->state_file);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (m->operational_state != operstate) {
|
||||
m->operational_state = operstate;
|
||||
if (strv_extend(&p, "OperationalState") < 0)
|
||||
log_oom();
|
||||
}
|
||||
|
||||
if (m->carrier_state != carrier_state) {
|
||||
m->carrier_state = carrier_state;
|
||||
if (strv_extend(&p, "CarrierState") < 0)
|
||||
log_oom();
|
||||
}
|
||||
|
||||
if (m->address_state != address_state) {
|
||||
m->address_state = address_state;
|
||||
if (strv_extend(&p, "AddressState") < 0)
|
||||
log_oom();
|
||||
}
|
||||
|
||||
if (p) {
|
||||
r = manager_send_changed_strv(m, p);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Could not emit changed properties: %m");
|
||||
}
|
||||
|
||||
m->dirty = false;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
(void) unlink(m->state_file);
|
||||
(void) unlink(temp_path);
|
||||
|
||||
return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
|
||||
}
|
||||
|
||||
static int manager_dirty_handler(sd_event_source *s, void *userdata) {
|
||||
Manager *m = userdata;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (m->dirty)
|
||||
manager_save(m);
|
||||
if (m->dirty) {
|
||||
r = manager_save(m);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file);
|
||||
}
|
||||
|
||||
SET_FOREACH(link, m->dirty_links)
|
||||
(void) link_save_and_clean(link);
|
||||
SET_FOREACH(link, m->dirty_links) {
|
||||
r = link_save_and_clean(link);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -929,10 +512,15 @@ int manager_start(Manager *m) {
|
||||
/* The dirty handler will deal with future serialization, but the first one
|
||||
must be done explicitly. */
|
||||
|
||||
manager_save(m);
|
||||
r = manager_save(m);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file);
|
||||
|
||||
HASHMAP_FOREACH(link, m->links)
|
||||
(void) link_save(link);
|
||||
HASHMAP_FOREACH(link, m->links) {
|
||||
r = link_save(link);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1155,13 +743,6 @@ Link* manager_find_uplink(Manager *m, Link *exclude) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void manager_dirty(Manager *manager) {
|
||||
assert(manager);
|
||||
|
||||
/* the serialized state in /run is no longer up-to-date */
|
||||
manager->dirty = true;
|
||||
}
|
||||
|
||||
static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
||||
const sd_bus_error *e;
|
||||
int r;
|
||||
|
@ -100,8 +100,6 @@ bool manager_should_reload(Manager *m);
|
||||
|
||||
int manager_enumerate(Manager *m);
|
||||
|
||||
void manager_dirty(Manager *m);
|
||||
|
||||
Link* manager_find_uplink(Manager *m, Link *exclude);
|
||||
|
||||
int manager_set_hostname(Manager *m, const char *hostname);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "networkd-dhcp6.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-ndisc.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
682
src/network/networkd-state-file.c
Normal file
682
src/network/networkd-state-file.c
Normal file
@ -0,0 +1,682 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <linux/if.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dns-domain.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "network-internal.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-manager-bus.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "ordered-set.h"
|
||||
#include "set.h"
|
||||
#include "strv.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) {
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(dns);
|
||||
|
||||
if (dns->ifindex != 0 && dns->ifindex != ifindex)
|
||||
return 0;
|
||||
|
||||
p = in_addr_full_to_string(dns);
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
r = ordered_set_put_strdup(s, p);
|
||||
if (r == -EEXIST)
|
||||
return 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) {
|
||||
int r, c = 0;
|
||||
|
||||
assert(s);
|
||||
assert(dns || n == 0);
|
||||
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
r = ordered_set_put_dns_server(s, ifindex, dns[i]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
c += r;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) {
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(address);
|
||||
|
||||
r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_set_consume(s, p);
|
||||
if (r == -EEXIST)
|
||||
return 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ordered_set_put_in4_addrv(
|
||||
OrderedSet *s,
|
||||
const struct in_addr *addresses,
|
||||
size_t n,
|
||||
bool (*predicate)(const struct in_addr *addr)) {
|
||||
|
||||
int r, c = 0;
|
||||
|
||||
assert(s);
|
||||
assert(n == 0 || addresses);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (predicate && !predicate(&addresses[i]))
|
||||
continue;
|
||||
r = ordered_set_put_in4_addr(s, addresses+i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
c += r;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int manager_save(Manager *m) {
|
||||
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
|
||||
const char *operstate_str, *carrier_state_str, *address_state_str;
|
||||
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
|
||||
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
|
||||
LinkAddressState address_state = LINK_ADDRESS_STATE_OFF;
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
_cleanup_strv_free_ char **p = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(m->state_file);
|
||||
|
||||
/* We add all NTP and DNS server to a set, to filter out duplicates */
|
||||
dns = ordered_set_new(&string_hash_ops);
|
||||
if (!dns)
|
||||
return -ENOMEM;
|
||||
|
||||
ntp = ordered_set_new(&string_hash_ops);
|
||||
if (!ntp)
|
||||
return -ENOMEM;
|
||||
|
||||
sip = ordered_set_new(&string_hash_ops);
|
||||
if (!sip)
|
||||
return -ENOMEM;
|
||||
|
||||
search_domains = ordered_set_new(&dns_name_hash_ops);
|
||||
if (!search_domains)
|
||||
return -ENOMEM;
|
||||
|
||||
route_domains = ordered_set_new(&dns_name_hash_ops);
|
||||
if (!route_domains)
|
||||
return -ENOMEM;
|
||||
|
||||
HASHMAP_FOREACH(link, m->links) {
|
||||
const struct in_addr *addresses;
|
||||
|
||||
if (link->flags & IFF_LOOPBACK)
|
||||
continue;
|
||||
|
||||
if (link->operstate > operstate)
|
||||
operstate = link->operstate;
|
||||
|
||||
if (link->carrier_state > carrier_state)
|
||||
carrier_state = link->carrier_state;
|
||||
|
||||
if (link->address_state > address_state)
|
||||
address_state = link->address_state;
|
||||
|
||||
if (!link->network)
|
||||
continue;
|
||||
|
||||
/* First add the static configured entries */
|
||||
if (link->n_dns != (unsigned) -1)
|
||||
r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns);
|
||||
else
|
||||
r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!link->dhcp_lease)
|
||||
continue;
|
||||
|
||||
/* Secondly, add the entries acquired via DHCP */
|
||||
if (link->network->dhcp_use_dns) {
|
||||
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
|
||||
if (r > 0) {
|
||||
r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_ntp) {
|
||||
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
|
||||
if (r > 0) {
|
||||
r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_sip) {
|
||||
r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
|
||||
if (r > 0) {
|
||||
r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
|
||||
const char *domainname;
|
||||
char **domains = NULL;
|
||||
|
||||
OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains;
|
||||
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
|
||||
if (r >= 0) {
|
||||
r = ordered_set_put_strdup(target_domains, domainname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r != -ENODATA)
|
||||
return r;
|
||||
|
||||
r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
|
||||
if (r >= 0) {
|
||||
r = ordered_set_put_strdupv(target_domains, domains);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
|
||||
carrier_state = LINK_CARRIER_STATE_CARRIER;
|
||||
|
||||
operstate_str = link_operstate_to_string(operstate);
|
||||
assert(operstate_str);
|
||||
|
||||
carrier_state_str = link_carrier_state_to_string(carrier_state);
|
||||
assert(carrier_state_str);
|
||||
|
||||
address_state_str = link_address_state_to_string(address_state);
|
||||
assert(address_state_str);
|
||||
|
||||
r = fopen_temporary(m->state_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) fchmod(fileno(f), 0644);
|
||||
|
||||
fprintf(f,
|
||||
"# This is private data. Do not parse.\n"
|
||||
"OPER_STATE=%s\n"
|
||||
"CARRIER_STATE=%s\n"
|
||||
"ADDRESS_STATE=%s\n",
|
||||
operstate_str, carrier_state_str, address_state_str);
|
||||
|
||||
ordered_set_print(f, "DNS=", dns);
|
||||
ordered_set_print(f, "NTP=", ntp);
|
||||
ordered_set_print(f, "SIP=", sip);
|
||||
ordered_set_print(f, "DOMAINS=", search_domains);
|
||||
ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = conservative_rename(temp_path, m->state_file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
temp_path = mfree(temp_path);
|
||||
|
||||
if (m->operational_state != operstate) {
|
||||
m->operational_state = operstate;
|
||||
if (strv_extend(&p, "OperationalState") < 0)
|
||||
log_oom();
|
||||
}
|
||||
|
||||
if (m->carrier_state != carrier_state) {
|
||||
m->carrier_state = carrier_state;
|
||||
if (strv_extend(&p, "CarrierState") < 0)
|
||||
log_oom();
|
||||
}
|
||||
|
||||
if (m->address_state != address_state) {
|
||||
m->address_state = address_state;
|
||||
if (strv_extend(&p, "AddressState") < 0)
|
||||
log_oom();
|
||||
}
|
||||
|
||||
if (p) {
|
||||
r = manager_send_changed_strv(m, p);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not emit changed properties, ignoring: %m");
|
||||
}
|
||||
|
||||
m->dirty = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
|
||||
bool space = false;
|
||||
Link *link;
|
||||
|
||||
assert(f);
|
||||
assert(prefix);
|
||||
|
||||
if (hashmap_isempty(h))
|
||||
return;
|
||||
|
||||
fputs(prefix, f);
|
||||
HASHMAP_FOREACH(link, h) {
|
||||
if (space)
|
||||
fputc(' ', f);
|
||||
|
||||
fprintf(f, "%i", link->ifindex);
|
||||
space = true;
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
|
||||
for (unsigned j = 0; j < n_dns; j++) {
|
||||
const char *str;
|
||||
|
||||
if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
|
||||
continue;
|
||||
|
||||
str = in_addr_full_to_string(dns[j]);
|
||||
if (!str)
|
||||
continue;
|
||||
|
||||
if (*space)
|
||||
fputc(' ', f);
|
||||
fputs(str, f);
|
||||
*space = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void serialize_addresses(
|
||||
FILE *f,
|
||||
const char *lvalue,
|
||||
bool *space,
|
||||
char **addresses,
|
||||
sd_dhcp_lease *lease,
|
||||
bool conditional,
|
||||
sd_dhcp_lease_server_type_t what,
|
||||
sd_dhcp6_lease *lease6,
|
||||
bool conditional6,
|
||||
int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**),
|
||||
int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) {
|
||||
|
||||
bool _space = false;
|
||||
int r;
|
||||
|
||||
if (!space)
|
||||
space = &_space;
|
||||
|
||||
if (lvalue)
|
||||
fprintf(f, "%s=", lvalue);
|
||||
fputstrv(f, addresses, NULL, space);
|
||||
|
||||
if (lease && conditional) {
|
||||
const struct in_addr *lease_addresses;
|
||||
|
||||
r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses);
|
||||
if (r > 0)
|
||||
serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local);
|
||||
}
|
||||
|
||||
if (lease6 && conditional6 && lease6_get_addr) {
|
||||
const struct in6_addr *in6_addrs;
|
||||
|
||||
r = lease6_get_addr(lease6, &in6_addrs);
|
||||
if (r > 0)
|
||||
serialize_in6_addrs(f, in6_addrs, r, space);
|
||||
}
|
||||
|
||||
if (lease6 && conditional6 && lease6_get_fqdn) {
|
||||
char **in6_hosts;
|
||||
|
||||
r = lease6_get_fqdn(lease6, &in6_hosts);
|
||||
if (r > 0)
|
||||
fputstrv(f, in6_hosts, NULL, space);
|
||||
}
|
||||
|
||||
if (lvalue)
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
int link_save(Link *link) {
|
||||
const char *admin_state, *oper_state, *carrier_state, *address_state;
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->state_file);
|
||||
assert(link->lease_file);
|
||||
assert(link->manager);
|
||||
|
||||
if (link->state == LINK_STATE_LINGER)
|
||||
return 0;
|
||||
|
||||
link_lldp_save(link);
|
||||
|
||||
admin_state = link_state_to_string(link->state);
|
||||
assert(admin_state);
|
||||
|
||||
oper_state = link_operstate_to_string(link->operstate);
|
||||
assert(oper_state);
|
||||
|
||||
carrier_state = link_carrier_state_to_string(link->carrier_state);
|
||||
assert(carrier_state);
|
||||
|
||||
address_state = link_address_state_to_string(link->address_state);
|
||||
assert(address_state);
|
||||
|
||||
r = fopen_temporary(link->state_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) fchmod(fileno(f), 0644);
|
||||
|
||||
fprintf(f,
|
||||
"# This is private data. Do not parse.\n"
|
||||
"ADMIN_STATE=%s\n"
|
||||
"OPER_STATE=%s\n"
|
||||
"CARRIER_STATE=%s\n"
|
||||
"ADDRESS_STATE=%s\n",
|
||||
admin_state, oper_state, carrier_state, address_state);
|
||||
|
||||
if (link->network) {
|
||||
char **dhcp6_domains = NULL, **dhcp_domains = NULL;
|
||||
const char *dhcp_domainname = NULL, *p;
|
||||
bool space;
|
||||
|
||||
fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
|
||||
yes_no(link->network->required_for_online));
|
||||
|
||||
LinkOperationalStateRange st = link->network->required_operstate_for_online;
|
||||
fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s%s%s\n",
|
||||
strempty(link_operstate_to_string(st.min)),
|
||||
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
|
||||
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
|
||||
|
||||
fprintf(f, "ACTIVATION_POLICY=%s\n",
|
||||
activation_policy_to_string(link->network->activation_policy));
|
||||
|
||||
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
fputs("DNS=", f);
|
||||
space = false;
|
||||
if (link->n_dns != (unsigned) -1)
|
||||
link_save_dns(link, f, link->dns, link->n_dns, &space);
|
||||
else
|
||||
link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
|
||||
|
||||
serialize_addresses(f, NULL, &space,
|
||||
NULL,
|
||||
link->dhcp_lease,
|
||||
link->network->dhcp_use_dns,
|
||||
SD_DHCP_LEASE_DNS,
|
||||
link->dhcp6_lease,
|
||||
link->network->dhcp6_use_dns,
|
||||
sd_dhcp6_lease_get_dns,
|
||||
NULL);
|
||||
|
||||
/* Make sure to flush out old entries before we use the NDisc data */
|
||||
ndisc_vacuum(link);
|
||||
|
||||
if (link->network->ipv6_accept_ra_use_dns && link->ndisc_rdnss) {
|
||||
NDiscRDNSS *dd;
|
||||
|
||||
SET_FOREACH(dd, link->ndisc_rdnss)
|
||||
serialize_in6_addrs(f, &dd->address, 1, &space);
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
serialize_addresses(f, "NTP", NULL,
|
||||
link->ntp ?: link->network->ntp,
|
||||
link->dhcp_lease,
|
||||
link->network->dhcp_use_ntp,
|
||||
SD_DHCP_LEASE_NTP,
|
||||
link->dhcp6_lease,
|
||||
link->network->dhcp6_use_ntp,
|
||||
sd_dhcp6_lease_get_ntp_addrs,
|
||||
sd_dhcp6_lease_get_ntp_fqdn);
|
||||
|
||||
serialize_addresses(f, "SIP", NULL,
|
||||
NULL,
|
||||
link->dhcp_lease,
|
||||
link->network->dhcp_use_sip,
|
||||
SD_DHCP_LEASE_SIP,
|
||||
NULL, false, NULL, NULL);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
|
||||
if (link->dhcp_lease) {
|
||||
(void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
|
||||
(void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains);
|
||||
}
|
||||
if (link->dhcp6_lease)
|
||||
(void) sd_dhcp6_lease_get_domains(link->dhcp6_lease, &dhcp6_domains);
|
||||
}
|
||||
|
||||
fputs("DOMAINS=", f);
|
||||
space = false;
|
||||
ORDERED_SET_FOREACH(p, link->search_domains ?: link->network->search_domains)
|
||||
fputs_with_space(f, p, NULL, &space);
|
||||
|
||||
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
|
||||
if (dhcp_domainname)
|
||||
fputs_with_space(f, dhcp_domainname, NULL, &space);
|
||||
if (dhcp_domains)
|
||||
fputstrv(f, dhcp_domains, NULL, &space);
|
||||
if (dhcp6_domains)
|
||||
fputstrv(f, dhcp6_domains, NULL, &space);
|
||||
}
|
||||
|
||||
if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_YES) {
|
||||
NDiscDNSSL *dd;
|
||||
|
||||
SET_FOREACH(dd, link->ndisc_dnssl)
|
||||
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
fputs("ROUTE_DOMAINS=", f);
|
||||
space = false;
|
||||
ORDERED_SET_FOREACH(p, link->route_domains ?: link->network->route_domains)
|
||||
fputs_with_space(f, p, NULL, &space);
|
||||
|
||||
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
|
||||
if (dhcp_domainname)
|
||||
fputs_with_space(f, dhcp_domainname, NULL, &space);
|
||||
if (dhcp_domains)
|
||||
fputstrv(f, dhcp_domains, NULL, &space);
|
||||
if (dhcp6_domains)
|
||||
fputstrv(f, dhcp6_domains, NULL, &space);
|
||||
}
|
||||
|
||||
if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_ROUTE) {
|
||||
NDiscDNSSL *dd;
|
||||
|
||||
SET_FOREACH(dd, link->ndisc_dnssl)
|
||||
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
|
||||
}
|
||||
|
||||
fputc('\n', f);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
fprintf(f, "LLMNR=%s\n",
|
||||
resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr));
|
||||
|
||||
/************************************************************/
|
||||
|
||||
fprintf(f, "MDNS=%s\n",
|
||||
resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns));
|
||||
|
||||
/************************************************************/
|
||||
|
||||
int dns_default_route =
|
||||
link->dns_default_route >= 0 ? link->dns_default_route :
|
||||
link->network->dns_default_route;
|
||||
if (dns_default_route >= 0)
|
||||
fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route));
|
||||
|
||||
/************************************************************/
|
||||
|
||||
DnsOverTlsMode dns_over_tls_mode =
|
||||
link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode :
|
||||
link->network->dns_over_tls_mode;
|
||||
if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
|
||||
fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode));
|
||||
|
||||
/************************************************************/
|
||||
|
||||
DnssecMode dnssec_mode =
|
||||
link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode :
|
||||
link->network->dnssec_mode;
|
||||
if (dnssec_mode != _DNSSEC_MODE_INVALID)
|
||||
fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode));
|
||||
|
||||
/************************************************************/
|
||||
|
||||
Set *nta_anchors = link->dnssec_negative_trust_anchors;
|
||||
if (set_isempty(nta_anchors))
|
||||
nta_anchors = link->network->dnssec_negative_trust_anchors;
|
||||
|
||||
if (!set_isempty(nta_anchors)) {
|
||||
const char *n;
|
||||
|
||||
fputs("DNSSEC_NTA=", f);
|
||||
space = false;
|
||||
SET_FOREACH(n, nta_anchors)
|
||||
fputs_with_space(f, n, NULL, &space);
|
||||
fputc('\n', f);
|
||||
}
|
||||
}
|
||||
|
||||
print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
|
||||
print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
|
||||
|
||||
if (link->dhcp_lease) {
|
||||
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fprintf(f,
|
||||
"DHCP_LEASE=%s\n",
|
||||
link->lease_file);
|
||||
} else
|
||||
(void) unlink(link->lease_file);
|
||||
|
||||
r = link_serialize_dhcp6_client(link, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = conservative_rename(temp_path, link->state_file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
temp_path = mfree(temp_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void link_dirty(Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
/* The serialized state in /run is no longer up-to-date. */
|
||||
|
||||
/* Also mark manager dirty as link is dirty */
|
||||
link->manager->dirty = true;
|
||||
|
||||
r = set_ensure_put(&link->manager->dirty_links, NULL, link);
|
||||
if (r <= 0)
|
||||
/* Ignore allocation errors and don't take another ref if the link was already dirty */
|
||||
return;
|
||||
link_ref(link);
|
||||
}
|
||||
|
||||
void link_clean(Link *link) {
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
/* The serialized state in /run is up-to-date */
|
||||
|
||||
link_unref(set_remove(link->manager->dirty_links, link));
|
||||
}
|
||||
|
||||
int link_save_and_clean(Link *link) {
|
||||
int r;
|
||||
|
||||
r = link_save(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
link_clean(link);
|
||||
return 0;
|
||||
}
|
12
src/network/networkd-state-file.h
Normal file
12
src/network/networkd-state-file.h
Normal file
@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Manager Manager;
|
||||
|
||||
void link_dirty(Link *link);
|
||||
void link_clean(Link *link);
|
||||
int link_save(Link *link);
|
||||
int link_save_and_clean(Link *link);
|
||||
|
||||
int manager_save(Manager *m);
|
@ -4563,7 +4563,7 @@ static int run_container(
|
||||
if (child_netns_fd < 0)
|
||||
return log_error_errno(errno, "Cannot open file %s: %m", arg_network_namespace_path);
|
||||
|
||||
r = fd_is_network_ns(child_netns_fd);
|
||||
r = fd_is_ns(child_netns_fd, CLONE_NEWNET);
|
||||
if (r == -EUCLEAN)
|
||||
log_debug_errno(r, "Cannot determine if passed network namespace path '%s' really refers to a network namespace, assuming it does.", arg_network_namespace_path);
|
||||
else if (r < 0)
|
||||
|
@ -959,7 +959,7 @@ static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
|
||||
/* We managed to get the unique name, then let's use that to
|
||||
* name our transient units. */
|
||||
|
||||
id = startswith(unique, ":1.");
|
||||
id = startswith(unique, ":");
|
||||
if (!id)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Unique name %s has unexpected format.",
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@ -276,44 +275,28 @@ int ask_password_plymouth(
|
||||
pollfd[POLL_INOTIFY].events = POLLIN;
|
||||
|
||||
for (;;) {
|
||||
int sleep_for = -1, j;
|
||||
usec_t timeout;
|
||||
|
||||
if (until > 0) {
|
||||
usec_t y;
|
||||
|
||||
y = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (y > until) {
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
sleep_for = (int) ((until - y) / USEC_PER_MSEC);
|
||||
}
|
||||
if (until > 0)
|
||||
timeout = usec_sub_unsigned(until, now(CLOCK_MONOTONIC));
|
||||
else
|
||||
timeout = USEC_INFINITY;
|
||||
|
||||
if (flag_file && access(flag_file, F_OK) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
|
||||
if (j < 0) {
|
||||
if (errno == EINTR)
|
||||
r = ppoll_usec(pollfd, notify >= 0 ? 2 : 1, timeout);
|
||||
if (r == -EINTR)
|
||||
continue;
|
||||
|
||||
r = -errno;
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
} else if (j == 0) {
|
||||
if (r == 0) {
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (pollfd[POLL_SOCKET].revents & POLLNVAL ||
|
||||
(notify >= 0 && pollfd[POLL_INOTIFY].revents & POLLNVAL)) {
|
||||
r = -EBADF;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
|
||||
(void) flush_fd(notify);
|
||||
|
||||
@ -513,21 +496,13 @@ int ask_password_tty(
|
||||
|
||||
for (;;) {
|
||||
_cleanup_(erase_char) char c;
|
||||
int sleep_for = -1, k;
|
||||
usec_t timeout;
|
||||
ssize_t n;
|
||||
|
||||
if (until > 0) {
|
||||
usec_t y;
|
||||
|
||||
y = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (y > until) {
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
sleep_for = (int) DIV_ROUND_UP(until - y, USEC_PER_MSEC);
|
||||
}
|
||||
if (until > 0)
|
||||
timeout = usec_sub_unsigned(until, now(CLOCK_MONOTONIC));
|
||||
else
|
||||
timeout = USEC_INFINITY;
|
||||
|
||||
if (flag_file)
|
||||
if (access(flag_file, F_OK) < 0) {
|
||||
@ -535,24 +510,16 @@ int ask_password_tty(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
|
||||
if (k < 0) {
|
||||
if (errno == EINTR)
|
||||
r = ppoll_usec(pollfd, notify >= 0 ? 2 : 1, timeout);
|
||||
if (r == -EINTR)
|
||||
continue;
|
||||
|
||||
r = -errno;
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
} else if (k == 0) {
|
||||
if (r == 0) {
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if ((pollfd[POLL_TTY].revents & POLLNVAL) ||
|
||||
(notify >= 0 && (pollfd[POLL_INOTIFY].revents & POLLNVAL))) {
|
||||
r = -EBADF;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) {
|
||||
(void) flush_fd(notify);
|
||||
|
||||
@ -875,38 +842,24 @@ int ask_password_agent(
|
||||
char passphrase[LINE_MAX+1];
|
||||
struct iovec iovec;
|
||||
struct ucred *ucred;
|
||||
usec_t timeout;
|
||||
ssize_t n;
|
||||
int k;
|
||||
usec_t t;
|
||||
|
||||
t = now(CLOCK_MONOTONIC);
|
||||
if (until > 0)
|
||||
timeout = usec_sub_unsigned(until, now(CLOCK_MONOTONIC));
|
||||
else
|
||||
timeout = USEC_INFINITY;
|
||||
|
||||
if (until > 0 && until <= t) {
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
k = poll(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1);
|
||||
if (k < 0) {
|
||||
if (errno == EINTR)
|
||||
r = ppoll_usec(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, timeout);
|
||||
if (r == -EINTR)
|
||||
continue;
|
||||
|
||||
r = -errno;
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (k <= 0) {
|
||||
if (r == 0) {
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (pollfd[FD_SOCKET].revents & POLLNVAL ||
|
||||
pollfd[FD_SIGNAL].revents & POLLNVAL ||
|
||||
(notify >= 0 && pollfd[FD_INOTIFY].revents & POLLNVAL)) {
|
||||
r = -EBADF;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (pollfd[FD_SIGNAL].revents & POLLIN) {
|
||||
r = -EINTR;
|
||||
goto finish;
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@ -12,6 +11,7 @@
|
||||
|
||||
#include "barrier.h"
|
||||
#include "fd-util.h"
|
||||
#include "io-util.h"
|
||||
#include "macro.h"
|
||||
|
||||
/**
|
||||
@ -219,14 +219,10 @@ static bool barrier_read(Barrier *b, int64_t comp) {
|
||||
uint64_t buf;
|
||||
int r;
|
||||
|
||||
r = poll(pfd, ELEMENTSOF(pfd), -1);
|
||||
if (r < 0) {
|
||||
if (IN_SET(errno, EAGAIN, EINTR))
|
||||
r = ppoll_usec(pfd, ELEMENTSOF(pfd), USEC_INFINITY);
|
||||
if (r == -EINTR)
|
||||
continue;
|
||||
goto error;
|
||||
}
|
||||
if (pfd[0].revents & POLLNVAL ||
|
||||
pfd[1].revents & POLLNVAL)
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (pfd[1].revents) {
|
||||
|
@ -882,6 +882,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||
"ProtectProc",
|
||||
"ProcSubset",
|
||||
"NetworkNamespacePath",
|
||||
"IPCNamespacePath",
|
||||
"LogNamespace"))
|
||||
return bus_append_string(m, field, eq);
|
||||
|
||||
@ -894,6 +895,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||
"PrivateNetwork",
|
||||
"PrivateUsers",
|
||||
"PrivateMounts",
|
||||
"PrivateIPC",
|
||||
"NoNewPrivileges",
|
||||
"SyslogLevelPrefix",
|
||||
"MemoryDenyWriteExecute",
|
||||
|
@ -1,6 +1,8 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum UnitFilePresetMode UnitFilePresetMode;
|
||||
typedef enum UnitFileChangeType UnitFileChangeType;
|
||||
typedef enum UnitFileFlags UnitFileFlags;
|
||||
@ -9,8 +11,6 @@ typedef struct UnitFileChange UnitFileChange;
|
||||
typedef struct UnitFileList UnitFileList;
|
||||
typedef struct UnitFileInstallInfo UnitFileInstallInfo;
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "macro.h"
|
||||
#include "path-lookup.h"
|
||||
|
@ -69,3 +69,11 @@ int namespace_flags_to_string(unsigned long flags, char **ret) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *namespace_single_flag_to_string(unsigned long flag) {
|
||||
for (unsigned i = 0; namespace_flag_map[i].name; i++)
|
||||
if (namespace_flag_map[i].flag == flag)
|
||||
return namespace_flag_map[i].name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
int namespace_flags_from_string(const char *name, unsigned long *ret);
|
||||
int namespace_flags_to_string(unsigned long flags, char **ret);
|
||||
const char *namespace_single_flag_to_string(unsigned long flag);
|
||||
|
||||
struct namespace_flag_map {
|
||||
unsigned long flag;
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <poll.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@ -15,6 +14,7 @@
|
||||
#include "bus-internal.h"
|
||||
#include "bus-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "io-util.h"
|
||||
#include "log.h"
|
||||
#include "main-func.h"
|
||||
#include "util.h"
|
||||
@ -181,8 +181,9 @@ static int run(int argc, char *argv[]) {
|
||||
for (;;) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
int events_a, events_b, fd;
|
||||
uint64_t timeout_a, timeout_b, t;
|
||||
struct timespec _ts, *ts;
|
||||
usec_t timeout_a, timeout_b, t;
|
||||
|
||||
assert_cc(sizeof(usec_t) == sizeof(uint64_t));
|
||||
|
||||
r = sd_bus_process(a, &m);
|
||||
if (r < 0)
|
||||
@ -235,23 +236,7 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get timeout: %m");
|
||||
|
||||
t = timeout_a;
|
||||
if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
|
||||
t = timeout_b;
|
||||
|
||||
if (t == (uint64_t) -1)
|
||||
ts = NULL;
|
||||
else {
|
||||
usec_t nw;
|
||||
|
||||
nw = now(CLOCK_MONOTONIC);
|
||||
if (t > nw)
|
||||
t -= nw;
|
||||
else
|
||||
t = 0;
|
||||
|
||||
ts = timespec_store(&_ts, t);
|
||||
}
|
||||
t = usec_sub_unsigned(MIN(timeout_a, timeout_b), now(CLOCK_MONOTONIC));
|
||||
|
||||
struct pollfd p[3] = {
|
||||
{ .fd = fd, .events = events_a },
|
||||
@ -259,13 +244,9 @@ static int run(int argc, char *argv[]) {
|
||||
{ .fd = STDOUT_FILENO, .events = events_b & POLLOUT },
|
||||
};
|
||||
|
||||
r = ppoll(p, ELEMENTSOF(p), ts, NULL);
|
||||
r = ppoll_usec(p, ELEMENTSOF(p), t);
|
||||
if (r < 0)
|
||||
return log_error_errno(errno, "ppoll() failed: %m");
|
||||
if (p[0].revents & POLLNVAL ||
|
||||
p[1].revents & POLLNVAL ||
|
||||
p[2].revents & POLLNVAL)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Invalid file descriptor to poll on?");
|
||||
return log_error_errno(r, "ppoll() failed: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -63,7 +63,7 @@ static void test_tmpdir(const char *id, const char *A, const char *B) {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_netns(void) {
|
||||
static void test_shareable_ns(unsigned long nsflag) {
|
||||
_cleanup_close_pair_ int s[2] = { -1, -1 };
|
||||
pid_t pid1, pid2, pid3;
|
||||
int r, n = 0;
|
||||
@ -80,7 +80,7 @@ static void test_netns(void) {
|
||||
assert_se(pid1 >= 0);
|
||||
|
||||
if (pid1 == 0) {
|
||||
r = setup_netns(s);
|
||||
r = setup_shareable_ns(s, nsflag);
|
||||
assert_se(r >= 0);
|
||||
_exit(r);
|
||||
}
|
||||
@ -89,7 +89,7 @@ static void test_netns(void) {
|
||||
assert_se(pid2 >= 0);
|
||||
|
||||
if (pid2 == 0) {
|
||||
r = setup_netns(s);
|
||||
r = setup_shareable_ns(s, nsflag);
|
||||
assert_se(r >= 0);
|
||||
exit(r);
|
||||
}
|
||||
@ -98,7 +98,7 @@ static void test_netns(void) {
|
||||
assert_se(pid3 >= 0);
|
||||
|
||||
if (pid3 == 0) {
|
||||
r = setup_netns(s);
|
||||
r = setup_shareable_ns(s, nsflag);
|
||||
assert_se(r >= 0);
|
||||
exit(r);
|
||||
}
|
||||
@ -121,6 +121,14 @@ static void test_netns(void) {
|
||||
assert_se(n == 1);
|
||||
}
|
||||
|
||||
static void test_netns(void) {
|
||||
test_shareable_ns(CLONE_NEWNET);
|
||||
}
|
||||
|
||||
static void test_ipcns(void) {
|
||||
test_shareable_ns(CLONE_NEWIPC);
|
||||
}
|
||||
|
||||
static void test_protect_kernel_logs(void) {
|
||||
int r;
|
||||
pid_t pid;
|
||||
@ -224,6 +232,7 @@ int main(int argc, char *argv[]) {
|
||||
test_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz);
|
||||
|
||||
test_netns();
|
||||
test_ipcns();
|
||||
test_protect_kernel_logs();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/magic.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
@ -67,18 +68,22 @@ static void test_path_is_temporary_fs(void) {
|
||||
assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT);
|
||||
}
|
||||
|
||||
static void test_fd_is_network_ns(void) {
|
||||
static void test_fd_is_ns(void) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
assert_se(fd_is_network_ns(STDIN_FILENO) == 0);
|
||||
assert_se(fd_is_network_ns(STDERR_FILENO) == 0);
|
||||
assert_se(fd_is_network_ns(STDOUT_FILENO) == 0);
|
||||
assert_se(fd_is_ns(STDIN_FILENO, CLONE_NEWNET) == 0);
|
||||
assert_se(fd_is_ns(STDERR_FILENO, CLONE_NEWNET) == 0);
|
||||
assert_se(fd_is_ns(STDOUT_FILENO, CLONE_NEWNET) == 0);
|
||||
|
||||
assert_se((fd = open("/proc/self/ns/mnt", O_CLOEXEC|O_RDONLY)) >= 0);
|
||||
assert_se(IN_SET(fd_is_network_ns(fd), 0, -EUCLEAN));
|
||||
assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 0, -EUCLEAN));
|
||||
fd = safe_close(fd);
|
||||
|
||||
assert_se((fd = open("/proc/self/ns/ipc", O_CLOEXEC|O_RDONLY)) >= 0);
|
||||
assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWIPC), 1, -EUCLEAN));
|
||||
fd = safe_close(fd);
|
||||
|
||||
assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0);
|
||||
assert_se(IN_SET(fd_is_network_ns(fd), 1, -EUCLEAN));
|
||||
assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 1, -EUCLEAN));
|
||||
}
|
||||
|
||||
static void test_device_major_minor_valid(void) {
|
||||
@ -159,7 +164,7 @@ int main(int argc, char *argv[]) {
|
||||
test_is_symlink();
|
||||
test_path_is_fs_type();
|
||||
test_path_is_temporary_fs();
|
||||
test_fd_is_network_ns();
|
||||
test_fd_is_ns();
|
||||
test_device_major_minor_valid();
|
||||
test_device_path_make_canonical();
|
||||
|
||||
|
@ -72,6 +72,13 @@ static double ts_to_d(const struct timespec *ts) {
|
||||
return ts->tv_sec + (1.0e-9 * ts->tv_nsec);
|
||||
}
|
||||
|
||||
static uint32_t graceful_add_offset_1900_1970(time_t t) {
|
||||
/* Adds OFFSET_1900_1970 to t and returns it as 32bit value. This is handles overflows
|
||||
* gracefully in a deterministic and well-defined way by cutting off the top bits. */
|
||||
uint64_t a = (uint64_t) t + OFFSET_1900_1970;
|
||||
return (uint32_t) (a & UINT64_C(0xFFFFFFFF));
|
||||
}
|
||||
|
||||
static int manager_timeout(sd_event_source *source, usec_t usec, void *userdata) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
Manager *m = userdata;
|
||||
@ -121,7 +128,7 @@ static int manager_send_request(Manager *m) {
|
||||
*/
|
||||
assert_se(clock_gettime(clock_boottime_or_monotonic(), &m->trans_time_mon) >= 0);
|
||||
assert_se(clock_gettime(CLOCK_REALTIME, &m->trans_time) >= 0);
|
||||
ntpmsg.trans_time.sec = htobe32(m->trans_time.tv_sec + OFFSET_1900_1970);
|
||||
ntpmsg.trans_time.sec = htobe32(graceful_add_offset_1900_1970(m->trans_time.tv_sec));
|
||||
ntpmsg.trans_time.frac = htobe32(m->trans_time.tv_nsec);
|
||||
|
||||
server_address_pretty(m->current_server_address, &pretty);
|
||||
@ -476,7 +483,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
|
||||
m->missed_replies = 0;
|
||||
|
||||
/* check our "time cookie" (we just stored nanoseconds in the fraction field) */
|
||||
if (be32toh(ntpmsg.origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 ||
|
||||
if (be32toh(ntpmsg.origin_time.sec) != graceful_add_offset_1900_1970(m->trans_time.tv_sec) ||
|
||||
be32toh(ntpmsg.origin_time.frac) != (unsigned long) m->trans_time.tv_nsec) {
|
||||
log_debug("Invalid reply; not our transmit time. Ignoring.");
|
||||
return 0;
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/prctl.h>
|
||||
@ -366,7 +365,7 @@ static int process_and_watch_password_files(bool watch) {
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int timeout = -1;
|
||||
usec_t timeout = USEC_INFINITY;
|
||||
|
||||
r = process_password_files();
|
||||
if (r < 0) {
|
||||
@ -385,16 +384,11 @@ static int process_and_watch_password_files(bool watch) {
|
||||
if (!watch)
|
||||
break;
|
||||
|
||||
if (poll(pollfd, _FD_MAX, timeout) < 0) {
|
||||
if (errno == EINTR)
|
||||
r = ppoll_usec(pollfd, _FD_MAX, timeout);
|
||||
if (r == -EINTR)
|
||||
continue;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (pollfd[FD_SIGNAL].revents & POLLNVAL ||
|
||||
pollfd[FD_INOTIFY].revents & POLLNVAL)
|
||||
return -EBADF;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (pollfd[FD_INOTIFY].revents != 0)
|
||||
(void) flush_fd(notify);
|
||||
|
@ -111,6 +111,7 @@ IOWriteIOPSMax=
|
||||
IPAccounting=
|
||||
IPAddressAllow=
|
||||
IPAddressDeny=
|
||||
IPCNamespacePath=
|
||||
IPTOS=
|
||||
IPTTL=
|
||||
IgnoreOnIsolate=
|
||||
@ -151,6 +152,7 @@ MemorySwapMax=
|
||||
MessageQueueMaxMessages=
|
||||
MessageQueueMessageSize=
|
||||
MountAPIVFS=
|
||||
NetworkNamespacePath=
|
||||
NoDelay=
|
||||
NoExecPaths=
|
||||
NoNewPrivileges=
|
||||
@ -856,6 +858,7 @@ PivotRoot=
|
||||
Port=
|
||||
PowerKeyIgnoreInhibited=
|
||||
Private=
|
||||
PrivateIPC=
|
||||
PrivateDevices=
|
||||
PrivateNetwork=
|
||||
PrivateTmp=
|
||||
|
Loading…
x
Reference in New Issue
Block a user