mirror of
https://github.com/systemd/systemd
synced 2025-12-28 20:04:45 +01:00
Compare commits
No commits in common. "0a67dd8310065a35a2fba2229b89ea0ab3e651fe" and "e9eec8b5d2c106c5dd51382a155e6045c7c17c1a" have entirely different histories.
0a67dd8310
...
e9eec8b5d2
3
TODO
3
TODO
@ -76,6 +76,9 @@ Features:
|
||||
|
||||
* make use of new glibc 2.32 APIs sigabbrev_np() and strerrorname_np().
|
||||
|
||||
* cryptsetup: if keyfile specified in crypttab is AF_UNIX socket, connect to it
|
||||
and read from it (like we do elsewhere with READ_FULL_FILE_CONNECT_SOCKET)
|
||||
|
||||
* when main nspawn supervisor process gets suspended due to SIGSTOP/SIGTTOU or
|
||||
so, freeze the payload too.
|
||||
|
||||
|
||||
@ -53,36 +53,25 @@
|
||||
it is opened as a LUKS device; otherwise, it is assumed to be in
|
||||
raw dm-crypt (plain mode) format.</para>
|
||||
|
||||
<para>The four fields of <filename>/etc/crypttab</filename> are defined as follows:</para>
|
||||
<para>The first field contains the name of the resulting encrypted volume; its block device is set up
|
||||
below <filename>/dev/mapper/</filename>.</para>
|
||||
|
||||
<orderedlist>
|
||||
<para>The second field contains a path to the underlying block
|
||||
device or file, or a specification of a block device via
|
||||
<literal>UUID=</literal> followed by the UUID.</para>
|
||||
|
||||
<listitem><para>The first field contains the name of the resulting volume with decrypted data; its
|
||||
block device is set up below <filename>/dev/mapper/</filename>.</para></listitem>
|
||||
<para>The third field specifies an absolute path to a file with the encryption key. Optionally,
|
||||
the path may be followed by <literal>:</literal> and an fstab device specification (e.g. starting with
|
||||
<literal>LABEL=</literal> or similar); in which case the path is taken relative to the device file system
|
||||
root. If the field is not present or is <literal>none</literal> or <literal>-</literal>, a key file
|
||||
named after the volume to unlock (i.e. the first column of the line), suffixed with
|
||||
<filename>.key</filename> is automatically loaded from the <filename>/etc/cryptsetup-keys.d/</filename>
|
||||
and <filename>/run/cryptsetup-keys.d/</filename> directories, if present. Otherwise, the password has to
|
||||
be manually entered during system boot. For swap encryption, <filename>/dev/urandom</filename> may be
|
||||
used as key file.</para>
|
||||
|
||||
<listitem><para>The second field contains a path to the underlying block
|
||||
device or file, or a specification of a block device via
|
||||
<literal>UUID=</literal> followed by the UUID.</para></listitem>
|
||||
|
||||
<listitem><para>The third field specifies an absolute path to a file with the encryption
|
||||
key. Optionally, the path may be followed by <literal>:</literal> and an fstab device specification
|
||||
(e.g. starting with <literal>LABEL=</literal> or similar); in which case the path is taken relative to
|
||||
the device file system root. If the field is not present or is <literal>none</literal> or
|
||||
<literal>-</literal>, a key file named after the volume to unlock (i.e. the first column of the line),
|
||||
suffixed with <filename>.key</filename> is automatically loaded from the
|
||||
<filename>/etc/cryptsetup-keys.d/</filename> and <filename>/run/cryptsetup-keys.d/</filename>
|
||||
directories, if present. Otherwise, the password has to be manually entered during system boot. For
|
||||
swap encryption, <filename>/dev/urandom</filename> may be used as key file, resulting in a randomized
|
||||
key.</para>
|
||||
|
||||
<para>If the specified key file path refers to an <constant>AF_UNIX</constant> stream socket in the
|
||||
file system, the key is acquired by connecting to the socket and reading it from the connection. This
|
||||
allows the implementation of a service to provide key information dynamically, at the moment when it is
|
||||
needed. For details see below.</para></listitem>
|
||||
|
||||
<listitem><para>The fourth field, if present, is a comma-delimited list of options. The suppported
|
||||
options are listed below.</para></listitem>
|
||||
</orderedlist>
|
||||
<para>The fourth field, if present, is a comma-delimited list of
|
||||
options. The following options are recognized:</para>
|
||||
|
||||
<variablelist class='fstab-options'>
|
||||
|
||||
@ -510,34 +499,6 @@
|
||||
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title><constant>AF_UNIX</constant> Key Files</title>
|
||||
|
||||
<para>If the key file path (as specified in the third column of <filename>/etc/crypttab</filename>
|
||||
entries, see above) refers to an <constant>AF_UNIX</constant> stream socket in the file system, the key
|
||||
is acquired by connecting to the socket and reading the key from the connection. The connection is made
|
||||
from an <constant>AF_UNIX</constant> socket name in the abstract namespace, see <citerefentry
|
||||
project='man-pages'><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
||||
details. The source socket name is chosen according the following format:</para>
|
||||
|
||||
<programlisting><constant>NUL</constant> <replaceable>RANDOM</replaceable> <literal>/cryptsetup/</literal> <replaceable>VOLUME</replaceable></programlisting>
|
||||
|
||||
<para>In other words: a <constant>NUL</constant> byte (as required for abstract namespace sockets),
|
||||
followed by a random string (consisting of alphabenumeric characters only), followed by the literal
|
||||
string <literal>/cryptsetup/</literal>, followed by the name of the volume to acquire they key
|
||||
for. Example (for a volume <literal>myvol</literal>):</para>
|
||||
|
||||
<example><programlisting>\0d7067f78d9827418/cryptsetup/myvol</programlisting></example>
|
||||
|
||||
<para>Services listening on the <constant>AF_UNIX</constant> stream socket may query the source socket
|
||||
name with <citerefentry
|
||||
project='man-pages'><refentrytitle>getpeername</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
|
||||
and use it to determine which key to send, allowing a single listening socket to serve keys for a
|
||||
multitude of volumes. If the PKCS#11 logic is used (see below) the socket source name is picked in
|
||||
identical fashion, except that the literal string <literal>/cryptsetup-pkcs11/</literal> is used. This is
|
||||
done so that services providing key material know that not a secret key is requested but an encrypted key
|
||||
that will be decrypted via the PKCS#11 logic to acquire the final secret key.</para>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<example>
|
||||
@ -568,6 +529,7 @@ external /dev/sda3 keyfile:LABEL=keydev keyfile-timeout=10s,cipher=xchac
|
||||
<para>A few notes on the above:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>We use RSA (and not ECC), since Yubikeys support PKCS#11 Decrypt() only for RSA keys</para></listitem>
|
||||
<listitem><para>We use RSA2048, which is the longest key size current Yubikeys support</para></listitem>
|
||||
<listitem><para>LUKS key size must be shorter than 2048bit due to RSA padding, hence we use 128 bytes</para></listitem>
|
||||
<listitem><para>We use Yubikey key slot 9d, since that's apparently the keyslot to use for decryption purposes,
|
||||
|
||||
@ -582,10 +582,6 @@ manpages = [
|
||||
'SD_EVENT_PRIORITY_NORMAL',
|
||||
'sd_event_source_get_priority'],
|
||||
''],
|
||||
['sd_event_source_set_ratelimit',
|
||||
'3',
|
||||
['sd_event_source_get_ratelimit', 'sd_event_source_is_ratelimited'],
|
||||
''],
|
||||
['sd_event_source_set_userdata', '3', ['sd_event_source_get_userdata'], ''],
|
||||
['sd_event_source_unref',
|
||||
'3',
|
||||
|
||||
@ -56,7 +56,6 @@
|
||||
<citerefentry><refentrytitle>sd_event_source_get_pending</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_ratelimit</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
@ -148,7 +147,6 @@
|
||||
<citerefentry><refentrytitle>sd_event_source_get_pending</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_ratelimit</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
|
||||
@ -147,8 +147,7 @@
|
||||
<citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_add_inotify</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_ratelimit</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@ -1,148 +0,0 @@
|
||||
<?xml version='1.0'?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
|
||||
<refentry id="sd_event_source_set_ratelimit" xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>sd_event_source_set_ratelimit</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>sd_event_source_set_ratelimit</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>sd_event_source_set_ratelimit</refname>
|
||||
<refname>sd_event_source_get_ratelimit</refname>
|
||||
<refname>sd_event_source_is_ratelimited</refname>
|
||||
|
||||
<refpurpose>Configure rate limiting on event sources</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<funcsynopsis>
|
||||
<funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_source_set_ratelimit</function></funcdef>
|
||||
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
|
||||
<paramdef>uint64_t <parameter>interval_usec</parameter></paramdef>
|
||||
<paramdef>unsigned <parameter>burst</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_source_get_ratelimit</function></funcdef>
|
||||
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
|
||||
<paramdef>uint64_t* <parameter>ret_interval_usec</parameter></paramdef>
|
||||
<paramdef>unsigned* <parameter>ret_burst</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_source_is_ratelimited</function></funcdef>
|
||||
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><function>sd_event_source_set_ratelimit()</function> may be used to enforce rate limiting on an
|
||||
event source. When used an event source will be temporarily turned off when it fires more often then a
|
||||
specified burst number within a specified time interval. This is useful as simple mechanism to avoid
|
||||
event source starvation if high priority event sources fire very frequently.</para>
|
||||
|
||||
<para>Pass the event source to operate on as first argument, a time interval in microseconds as second
|
||||
argument and a maximum dispatch limit ("burst") as third parameter. Whenever the event source is
|
||||
dispatched more often than the specified burst within the specified interval it is placed in a mode
|
||||
similar to being disabled with
|
||||
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
and the <constant>SD_EVENT_OFF</constant> parameter. However it is disabled only temporarily – once the
|
||||
specified interval is over regular operation resumes. It is again disabled temporarily once the specified rate
|
||||
limiting is hit the next time. If either the interval or the burst value are specified as zero, rate
|
||||
limiting is turned off. By default event sources do not have rate limiting enabled. Note that rate
|
||||
limiting and disabling via <function>sd_event_source_set_enabled()</function> are independent of each
|
||||
other, and an event source will only effect event loop wake-ups and is dispatched while it both is
|
||||
enabled and rate limiting is not in effect.</para>
|
||||
|
||||
<para><function>sd_event_source_get_ratelimit()</function> may be used to query the current rate limiting
|
||||
parameters set on the event source object <parameter>source</parameter>. The previously set interval and
|
||||
burst vales are returned in the second and third argument.</para>
|
||||
|
||||
<para><function>sd_event_source_is_ratelimited()</function> may be used to query whether the event source
|
||||
is currently affected by rate limiting, i.e. it has recently hit the rate limit and is currently
|
||||
temporarily disabled due to that.</para>
|
||||
|
||||
<para>Rate limiting is currently implemented for I/O, timer, signal, defer and inotify event
|
||||
sources.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
<para>On success, <function>sd_event_source_set_ratelimit()</function> and
|
||||
<function>sd_event_source_get_ratelimit()</function> return a non-negative integer. On failure, they
|
||||
return a negative errno-style error code. <function>sd_event_source_is_ratelimited</function> returns
|
||||
zero if rate limiting is currently not in effect and greater than zero if it is in effect; it returns a
|
||||
negative errno-style error code on failure.</para>
|
||||
|
||||
<refsect2>
|
||||
<title>Errors</title>
|
||||
|
||||
<para>Returned errors may indicate the following problems:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><constant>-EINVAL</constant></term>
|
||||
|
||||
<listitem><para><parameter>source</parameter> is not a valid pointer to an
|
||||
<structname>sd_event_source</structname> object.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-ECHILD</constant></term>
|
||||
|
||||
<listitem><para>The event loop has been created in a different process.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-EDOM</constant></term>
|
||||
|
||||
<listitem><para>It was attempted to use the rate limiting feature on an event source type that does
|
||||
not support rate limiting.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-ENOEXEC</constant></term>
|
||||
|
||||
<listitem><para><function>sd_event_source_get_ratelimit()</function> was called on a event source
|
||||
that doesn't have rate limiting configured.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<xi:include href="libsystemd-pkgconfig.xml" />
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
|
||||
<para>
|
||||
<citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_add_inotify</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@ -68,8 +68,8 @@
|
||||
<term><option>--key=</option></term>
|
||||
|
||||
<listitem><para>Specify the path to a file or <constant>AF_UNIX</constant> stream socket to read the
|
||||
secret server key corresponding to the certificate specified with <option>--cert=</option> from. The
|
||||
key must be in PEM format.</para></listitem>
|
||||
server key corresponding to the certificate specified with <option>--cert=</option> from. The key
|
||||
must be in PEM format.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
||||
@ -180,7 +180,7 @@
|
||||
<varlistentry>
|
||||
<term><option>--key=</option></term>
|
||||
|
||||
<listitem><para>Takes a path to a SSL secret key file in PEM format. Defaults to
|
||||
<listitem><para> Takes a path to a SSL key file in PEM format. Defaults to
|
||||
<filename>&CERTIFICATE_ROOT;/private/journal-remote.pem</filename>. This option can be used with
|
||||
<option>--listen-https=</option>. If the path refers to an <constant>AF_UNIX</constant> stream socket
|
||||
in the file system a connection is made to it and the key read from it.</para></listitem>
|
||||
|
||||
@ -364,15 +364,17 @@
|
||||
<varlistentry>
|
||||
<term><varname>LinkLocalAddressing=</varname></term>
|
||||
<listitem>
|
||||
<para>Enables link-local address autoconfiguration. Accepts <option>yes</option>,
|
||||
<option>no</option>, <option>ipv4</option>, and <option>ipv6</option>. An IPv6 link-local address
|
||||
is configured when <option>yes</option> or <option>ipv6</option>. An IPv4 link-local address is
|
||||
configured when <option>yes</option> or <option>ipv4</option> and when DHCPv4 autoconfiguration
|
||||
has been unsuccessful for some time. (IPv4 link-local address autoconfiguration will usually
|
||||
happen in parallel with repeated attempts to acquire a DHCPv4 lease).</para>
|
||||
|
||||
<para>Defaults to <option>no</option> when <varname>Bridge=yes</varname> is set, and
|
||||
<option>ipv6</option> otherwise.</para>
|
||||
<para>Enables link-local address autoconfiguration. Accepts <literal>yes</literal>,
|
||||
<literal>no</literal>, <literal>ipv4</literal>, <literal>ipv6</literal>,
|
||||
<literal>fallback</literal>, or <literal>ipv4-fallback</literal>. If
|
||||
<literal>fallback</literal> or <literal>ipv4-fallback</literal> is specified, then an IPv4
|
||||
link-local address is configured only when DHCPv4 fails. If <literal>fallback</literal>,
|
||||
an IPv6 link-local address is always configured, and if <literal>ipv4-fallback</literal>,
|
||||
the address is not configured. Note that, the fallback mechanism works only when DHCPv4
|
||||
client is enabled, that is, it requires <literal>DHCP=yes</literal> or
|
||||
<literal>DHCP=ipv4</literal>. If <varname>Bridge=</varname> is set, defaults to
|
||||
<literal>no</literal>, and if not, defaults to <literal>ipv6</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -1662,10 +1664,9 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
|
||||
<term><varname>MaxAttempts=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies how many times the DHCPv4 client configuration should be attempted. Takes a
|
||||
number or <literal>infinity</literal>. Defaults to <literal>infinity</literal>. Note that the
|
||||
time between retries is increased exponentially, up to approximately one per minute, so the
|
||||
network will not be overloaded even if this number is high. The default is suitable in most
|
||||
circumstances.</para>
|
||||
number or <literal>infinity</literal>. Defaults to <literal>infinity</literal>.
|
||||
Note that the time between retries is increased exponentially, so the network will not be
|
||||
overloaded even if this number is high.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
@ -472,13 +472,12 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
|
||||
int read_full_stream_full(
|
||||
FILE *f,
|
||||
const char *filename,
|
||||
uint64_t offset,
|
||||
size_t size,
|
||||
ReadFullFileFlags flags,
|
||||
char **ret_contents,
|
||||
size_t *ret_size) {
|
||||
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
struct stat st;
|
||||
size_t n, n_next, l;
|
||||
int fd, r;
|
||||
|
||||
@ -486,45 +485,32 @@ int read_full_stream_full(
|
||||
assert(ret_contents);
|
||||
assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
|
||||
|
||||
if (offset != UINT64_MAX && offset > LONG_MAX)
|
||||
return -ERANGE;
|
||||
|
||||
n_next = size != SIZE_MAX ? size : LINE_MAX; /* Start size */
|
||||
n_next = LINE_MAX; /* Start size */
|
||||
|
||||
fd = fileno(f);
|
||||
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see
|
||||
* fmemopen()), let's optimize our buffering */
|
||||
struct stat st;
|
||||
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's
|
||||
* optimize our buffering */
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
if (size == SIZE_MAX) {
|
||||
uint64_t rsize =
|
||||
LESS_BY((uint64_t) st.st_size, offset == UINT64_MAX ? 0 : offset);
|
||||
|
||||
/* Safety check */
|
||||
if (rsize > READ_FULL_BYTES_MAX)
|
||||
return -E2BIG;
|
||||
/* Safety check */
|
||||
if (st.st_size > READ_FULL_BYTES_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
/* Start with the right file size. Note that we increase the size to read
|
||||
* here by one, so that the first read attempt already makes us notice the
|
||||
* EOF. If the reported size of the file is zero, we avoid this logic
|
||||
* however, since quite likely it might be a virtual file in procfs that all
|
||||
* report a zero file size. */
|
||||
if (st.st_size > 0)
|
||||
n_next = rsize + 1;
|
||||
}
|
||||
/* Start with the right file size. Note that we increase the size
|
||||
* to read here by one, so that the first read attempt already
|
||||
* makes us notice the EOF. */
|
||||
if (st.st_size > 0)
|
||||
n_next = st.st_size + 1;
|
||||
|
||||
if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
|
||||
(void) warn_file_is_world_accessible(filename, &st, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (offset != UINT64_MAX && fseek(f, offset, SEEK_SET) < 0)
|
||||
return -errno;
|
||||
|
||||
n = l = 0;
|
||||
for (;;) {
|
||||
char *t;
|
||||
@ -561,11 +547,6 @@ int read_full_stream_full(
|
||||
if (feof(f))
|
||||
break;
|
||||
|
||||
if (size != SIZE_MAX) { /* If we got asked to read some specific size, we already sized the buffer right, hence leave */
|
||||
assert(l == size);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
|
||||
|
||||
/* Safety check */
|
||||
@ -624,18 +605,15 @@ finalize:
|
||||
int read_full_file_full(
|
||||
int dir_fd,
|
||||
const char *filename,
|
||||
uint64_t offset,
|
||||
size_t size,
|
||||
ReadFullFileFlags flags,
|
||||
const char *bind_name,
|
||||
char **ret_contents,
|
||||
size_t *ret_size) {
|
||||
char **contents, size_t *size) {
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(ret_contents);
|
||||
assert(contents);
|
||||
|
||||
r = xfopenat(dir_fd, filename, "re", 0, &f);
|
||||
if (r < 0) {
|
||||
@ -650,10 +628,6 @@ int read_full_file_full(
|
||||
if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
|
||||
return -ENXIO;
|
||||
|
||||
/* Seeking is not supported on AF_UNIX sockets */
|
||||
if (offset != UINT64_MAX)
|
||||
return -ESPIPE;
|
||||
|
||||
if (dir_fd == AT_FDCWD)
|
||||
r = sockaddr_un_set_path(&sa.un, filename);
|
||||
else {
|
||||
@ -707,7 +681,7 @@ int read_full_file_full(
|
||||
|
||||
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
||||
|
||||
return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
|
||||
return read_full_stream_full(f, filename, flags, contents, size);
|
||||
}
|
||||
|
||||
int executable_is_script(const char *path, char **interpreter) {
|
||||
|
||||
@ -60,14 +60,14 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
|
||||
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
|
||||
|
||||
int read_one_line_file(const char *filename, char **line);
|
||||
int read_full_file_full(int dir_fd, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, const char *bind_name, char **ret_contents, size_t *ret_size);
|
||||
static inline int read_full_file(const char *filename, char **ret_contents, size_t *ret_size) {
|
||||
return read_full_file_full(AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size);
|
||||
int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, const char *bind_name, char **contents, size_t *size);
|
||||
static inline int read_full_file(const char *filename, char **contents, size_t *size) {
|
||||
return read_full_file_full(AT_FDCWD, filename, 0, NULL, contents, size);
|
||||
}
|
||||
int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size);
|
||||
int read_full_stream_full(FILE *f, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, char **ret_contents, size_t *ret_size);
|
||||
static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_size) {
|
||||
return read_full_stream_full(f, NULL, UINT64_MAX, SIZE_MAX, 0, ret_contents, ret_size);
|
||||
int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
|
||||
static inline int read_full_stream(FILE *f, char **contents, size_t *size) {
|
||||
return read_full_stream_full(f, NULL, 0, contents, size);
|
||||
}
|
||||
|
||||
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
|
||||
|
||||
@ -28,12 +28,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
|
||||
|
||||
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
|
||||
scope type name##_from_string(const char *s) { \
|
||||
int b; \
|
||||
if (!s) \
|
||||
return -1; \
|
||||
int b = parse_boolean(s); \
|
||||
b = parse_boolean(s); \
|
||||
if (b == 0) \
|
||||
return (type) 0; \
|
||||
if (b > 0) \
|
||||
else if (b > 0) \
|
||||
return yes; \
|
||||
return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
|
||||
}
|
||||
|
||||
@ -2576,7 +2576,7 @@ static int acquire_credentials(
|
||||
|
||||
|
||||
if (source)
|
||||
r = read_full_file_full(AT_FDCWD, source, UINT64_MAX, SIZE_MAX, flags, bindname, &data, &size);
|
||||
r = read_full_file_full(AT_FDCWD, source, flags, bindname, &data, &size);
|
||||
else
|
||||
r = -ENOENT;
|
||||
if (r == -ENOENT &&
|
||||
|
||||
@ -1855,12 +1855,6 @@ static void mount_enumerate(Manager *m) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_event_source_set_ratelimit(m->mount_event_source, 1 * USEC_PER_SEC, 5);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to enable rate limit for mount events: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
(void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch");
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,29 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cryptsetup-keyfile.h"
|
||||
#include "fileio.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "memory-util.h"
|
||||
#include "path-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
int find_key_file(
|
||||
#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
|
||||
|
||||
int load_key_file(
|
||||
const char *key_file,
|
||||
char **search_path,
|
||||
const char *bindname,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
void **ret_key,
|
||||
size_t *ret_key_size) {
|
||||
|
||||
char **i;
|
||||
_cleanup_(erase_and_freep) char *buffer = NULL;
|
||||
_cleanup_free_ char *discovered_path = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
ssize_t n;
|
||||
int r;
|
||||
|
||||
assert(key_file);
|
||||
@ -20,38 +31,80 @@ int find_key_file(
|
||||
assert(ret_key_size);
|
||||
|
||||
if (strv_isempty(search_path) || path_is_absolute(key_file)) {
|
||||
fd = open(key_file, O_RDONLY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to load key file '%s': %m", key_file);
|
||||
} else {
|
||||
char **i;
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, key_file, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
bindname,
|
||||
(char**) ret_key, ret_key_size);
|
||||
STRV_FOREACH(i, search_path) {
|
||||
_cleanup_free_ char *joined;
|
||||
|
||||
joined = path_join(*i, key_file);
|
||||
if (!joined)
|
||||
return log_oom();
|
||||
|
||||
fd = open(joined, O_RDONLY|O_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
discovered_path = TAKE_PTR(joined);
|
||||
break;
|
||||
}
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to load key file '%s': %m", joined);
|
||||
}
|
||||
|
||||
if (!discovered_path) {
|
||||
/* Search path supplied, but file not found, report by returning NULL, but not failing */
|
||||
*ret_key = NULL;
|
||||
*ret_key_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(fd >= 0);
|
||||
key_file = discovered_path;
|
||||
}
|
||||
|
||||
if (key_file_size == 0) {
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file);
|
||||
|
||||
r = stat_verify_regular(&st);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load key file '%s': %m", key_file);
|
||||
return log_error_errno(r, "Key file is not a regular file: %m");
|
||||
|
||||
return 1;
|
||||
if (st.st_size == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
|
||||
if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
|
||||
char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
|
||||
"Key file larger (%s) than allowed maximum size (%s), refusing.",
|
||||
format_bytes(buf1, sizeof(buf1), st.st_size),
|
||||
format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
|
||||
}
|
||||
|
||||
if (key_file_offset >= (uint64_t) st.st_size)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
|
||||
|
||||
key_file_size = st.st_size - key_file_offset;
|
||||
}
|
||||
|
||||
STRV_FOREACH(i, search_path) {
|
||||
_cleanup_free_ char *joined;
|
||||
buffer = malloc(key_file_size);
|
||||
if (!buffer)
|
||||
return log_oom();
|
||||
|
||||
joined = path_join(*i, key_file);
|
||||
if (!joined)
|
||||
return log_oom();
|
||||
if (key_file_offset > 0)
|
||||
n = pread(fd, buffer, key_file_size, key_file_offset);
|
||||
else
|
||||
n = read(fd, buffer, key_file_size);
|
||||
if (n < 0)
|
||||
return log_error_errno(errno, "Failed to read key file '%s': %m", key_file);
|
||||
if (n == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, joined, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
bindname,
|
||||
(char**) ret_key, ret_key_size);
|
||||
if (r >= 0)
|
||||
return 1;
|
||||
if (r != -ENOENT)
|
||||
return log_error_errno(r, "Failed to load key file '%s': %m", key_file);
|
||||
}
|
||||
*ret_key = TAKE_PTR(buffer);
|
||||
*ret_key_size = (size_t) n;
|
||||
|
||||
/* Search path supplied, but file not found, report by returning NULL, but not failing */
|
||||
*ret_key = NULL;
|
||||
*ret_key_size = 0;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -4,9 +4,10 @@
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int find_key_file(
|
||||
int load_key_file(
|
||||
const char *key_file,
|
||||
char **search_path,
|
||||
const char *bindname,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
void **ret_key,
|
||||
size_t *ret_key_size);
|
||||
|
||||
@ -10,14 +10,13 @@
|
||||
#include "alloc-util.h"
|
||||
#include "ask-password-api.h"
|
||||
#include "cryptsetup-pkcs11.h"
|
||||
#include "cryptsetup-keyfile.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "pkcs11-util.h"
|
||||
#include "random-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
@ -96,7 +95,6 @@ static int pkcs11_callback(
|
||||
}
|
||||
|
||||
int decrypt_pkcs11_key(
|
||||
const char *volume_name,
|
||||
const char *friendly_name,
|
||||
const char *pkcs11_uri,
|
||||
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
|
||||
@ -128,19 +126,7 @@ int decrypt_pkcs11_key(
|
||||
|
||||
data.free_encrypted_key = false;
|
||||
} else {
|
||||
_cleanup_free_ char *bindname = NULL;
|
||||
|
||||
/* If we read the key via AF_UNIX, make this client recognizable */
|
||||
if (asprintf(&bindname, "@%" PRIx64"/cryptsetup-pkcs11/%s", random_u64(), volume_name) < 0)
|
||||
return log_oom();
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, key_file,
|
||||
key_file_offset == 0 ? UINT64_MAX : key_file_offset,
|
||||
key_file_size == 0 ? SIZE_MAX : key_file_size,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
bindname,
|
||||
(char**) &data.encrypted_key, &data.encrypted_key_size);
|
||||
r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
#if HAVE_P11KIT
|
||||
|
||||
int decrypt_pkcs11_key(
|
||||
const char *volume_name,
|
||||
const char *friendly_name,
|
||||
const char *pkcs11_uri,
|
||||
const char *key_file,
|
||||
@ -24,7 +23,6 @@ int decrypt_pkcs11_key(
|
||||
#else
|
||||
|
||||
static inline int decrypt_pkcs11_key(
|
||||
const char *volume_name,
|
||||
const char *friendly_name,
|
||||
const char *pkcs11_uri,
|
||||
const char *key_file,
|
||||
|
||||
@ -29,7 +29,6 @@
|
||||
#include "path-util.h"
|
||||
#include "pkcs11-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "random-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
@ -551,15 +550,6 @@ static int attach_tcrypt(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *make_bindname(const char *volume) {
|
||||
char *s;
|
||||
|
||||
if (asprintf(&s, "@%" PRIx64"/cryptsetup/%s", random_u64(), volume) < 0)
|
||||
return NULL;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int attach_luks_or_plain_or_bitlk(
|
||||
struct crypt_device *cd,
|
||||
const char *name,
|
||||
@ -646,7 +636,6 @@ static int attach_luks_or_plain_or_bitlk(
|
||||
bool processed = false;
|
||||
|
||||
r = decrypt_pkcs11_key(
|
||||
name,
|
||||
friendly,
|
||||
arg_pkcs11_uri,
|
||||
key_file, arg_keyfile_size, arg_keyfile_offset,
|
||||
@ -746,32 +735,15 @@ static int attach_luks_or_plain_or_bitlk(
|
||||
return log_error_errno(r, "Failed to activate: %m");
|
||||
|
||||
} else if (key_file) {
|
||||
_cleanup_(erase_and_freep) char *kfdata = NULL;
|
||||
_cleanup_free_ char *bindname = NULL;
|
||||
size_t kfsize;
|
||||
|
||||
/* If we read the key via AF_UNIX, make this client recognizable */
|
||||
bindname = make_bindname(name);
|
||||
if (!bindname)
|
||||
return log_oom();
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, key_file,
|
||||
arg_keyfile_offset == 0 ? UINT64_MAX : arg_keyfile_offset,
|
||||
arg_keyfile_size == 0 ? SIZE_MAX : arg_keyfile_size,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
bindname,
|
||||
&kfdata, &kfsize);
|
||||
if (r == -ENOENT) {
|
||||
log_error_errno(r, "Failed to activate, key file '%s' missing.", key_file);
|
||||
return -EAGAIN; /* Log actual error, but return EAGAIN */
|
||||
}
|
||||
|
||||
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, kfdata, kfsize, flags);
|
||||
r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
|
||||
if (r == -EPERM) {
|
||||
log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
|
||||
return -EAGAIN; /* Log actual error, but return EAGAIN */
|
||||
}
|
||||
if (r == -EINVAL) {
|
||||
log_error_errno(r, "Failed to activate with key file '%s'. (Key file missing?)", key_file);
|
||||
return -EAGAIN; /* Log actual error, but return EAGAIN */
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
|
||||
|
||||
@ -908,22 +880,16 @@ static int run(int argc, char *argv[]) {
|
||||
(void) mlockall(MCL_FUTURE);
|
||||
|
||||
if (!key_file) {
|
||||
_cleanup_free_ char *bindname = NULL;
|
||||
const char *fn;
|
||||
|
||||
bindname = make_bindname(argv[2]);
|
||||
if (!bindname)
|
||||
return log_oom();
|
||||
|
||||
/* If a key file is not explicitly specified, search for a key in a well defined
|
||||
* search path, and load it. */
|
||||
|
||||
fn = strjoina(argv[2], ".key");
|
||||
r = find_key_file(
|
||||
fn,
|
||||
STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
|
||||
bindname,
|
||||
&key_data, &key_data_size);
|
||||
r = load_key_file(fn,
|
||||
STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
|
||||
0, 0, /* Note we leave arg_keyfile_offset/arg_keyfile_size as something that only applies to arg_keyfile! */
|
||||
&key_data, &key_data_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
|
||||
@ -22,7 +22,6 @@
|
||||
#include "log.h"
|
||||
#include "logs-show.h"
|
||||
#include "main-func.h"
|
||||
#include "memory-util.h"
|
||||
#include "microhttpd-util.h"
|
||||
#include "os-util.h"
|
||||
#include "parse-util.h"
|
||||
@ -38,7 +37,7 @@ static char *arg_cert_pem = NULL;
|
||||
static char *arg_trust_pem = NULL;
|
||||
static const char *arg_directory = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_key_pem, erase_and_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_key_pem, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_cert_pem, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_trust_pem, freep);
|
||||
|
||||
@ -897,11 +896,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (arg_key_pem)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Key file specified twice");
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&arg_key_pem, NULL);
|
||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_key_pem, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read key file: %m");
|
||||
assert(arg_key_pem);
|
||||
@ -911,11 +906,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (arg_cert_pem)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Certificate file specified twice");
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&arg_cert_pem, NULL);
|
||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_cert_pem, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read certificate file: %m");
|
||||
assert(arg_cert_pem);
|
||||
@ -926,18 +917,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (arg_trust_pem)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"CA certificate file specified twice");
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&arg_trust_pem, NULL);
|
||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_trust_pem, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read CA certificate file: %m");
|
||||
assert(arg_trust_pem);
|
||||
break;
|
||||
#else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --trust= is not available.");
|
||||
"Option --trust is not available.");
|
||||
#endif
|
||||
case 'D':
|
||||
arg_directory = optarg;
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
#include "journal-remote-write.h"
|
||||
#include "journal-remote.h"
|
||||
#include "main-func.h"
|
||||
#include "memory-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "process-util.h"
|
||||
#include "rlimit-util.h"
|
||||
@ -1078,20 +1077,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
static int load_certificates(char **key, char **cert, char **trust) {
|
||||
int r;
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, arg_key ?: PRIV_KEY_FILE, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
key, NULL);
|
||||
r = read_full_file_full(AT_FDCWD, arg_key ?: PRIV_KEY_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, key, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read key from file '%s': %m",
|
||||
arg_key ?: PRIV_KEY_FILE);
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, arg_cert ?: CERT_FILE, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
cert, NULL);
|
||||
r = read_full_file_full(AT_FDCWD, arg_cert ?: CERT_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, cert, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read certificate from file '%s': %m",
|
||||
arg_cert ?: CERT_FILE);
|
||||
@ -1099,11 +1090,7 @@ static int load_certificates(char **key, char **cert, char **trust) {
|
||||
if (arg_trust_all)
|
||||
log_info("Certificate checking disabled.");
|
||||
else {
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, arg_trust ?: TRUST_FILE, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
trust, NULL);
|
||||
r = read_full_file_full(AT_FDCWD, arg_trust ?: TRUST_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, trust, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
|
||||
arg_trust ?: TRUST_FILE);
|
||||
@ -1119,8 +1106,7 @@ static int load_certificates(char **key, char **cert, char **trust) {
|
||||
static int run(int argc, char **argv) {
|
||||
_cleanup_(journal_remote_server_destroy) RemoteServer s = {};
|
||||
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
|
||||
_cleanup_(erase_and_freep) char *key = NULL;
|
||||
_cleanup_free_ char *cert = NULL, *trust = NULL;
|
||||
_cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
|
||||
int r;
|
||||
|
||||
log_show_color(true);
|
||||
|
||||
@ -38,9 +38,6 @@
|
||||
#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
|
||||
#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
|
||||
|
||||
#define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report
|
||||
* transient failure. */
|
||||
|
||||
typedef struct sd_dhcp_client_id {
|
||||
uint8_t type;
|
||||
union {
|
||||
@ -1190,7 +1187,7 @@ static int client_timeout_resend(
|
||||
|
||||
sd_dhcp_client *client = userdata;
|
||||
DHCP_CLIENT_DONT_DESTROY(client);
|
||||
usec_t next_timeout;
|
||||
usec_t next_timeout = 0;
|
||||
uint64_t time_now;
|
||||
uint32_t time_left;
|
||||
int r;
|
||||
@ -1206,14 +1203,17 @@ static int client_timeout_resend(
|
||||
switch (client->state) {
|
||||
|
||||
case DHCP_STATE_RENEWING:
|
||||
|
||||
time_left = (client->lease->t2 - client->lease->t1) / 2;
|
||||
if (time_left < 60)
|
||||
time_left = 60;
|
||||
|
||||
next_timeout = time_now + time_left * USEC_PER_SEC;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_STATE_REBINDING:
|
||||
|
||||
time_left = (client->lease->lifetime - client->lease->t2) / 2;
|
||||
if (time_left < 60)
|
||||
time_left = 60;
|
||||
@ -1230,20 +1230,24 @@ static int client_timeout_resend(
|
||||
r = client_start(client);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
log_dhcp_client(client, "REBOOTED");
|
||||
return 0;
|
||||
else {
|
||||
log_dhcp_client(client, "REBOOTED");
|
||||
return 0;
|
||||
}
|
||||
|
||||
case DHCP_STATE_INIT:
|
||||
case DHCP_STATE_INIT_REBOOT:
|
||||
case DHCP_STATE_SELECTING:
|
||||
case DHCP_STATE_REQUESTING:
|
||||
case DHCP_STATE_BOUND:
|
||||
if (client->attempt >= client->max_attempts)
|
||||
|
||||
if (client->attempt < client->max_attempts)
|
||||
client->attempt++;
|
||||
else
|
||||
goto error;
|
||||
|
||||
client->attempt++;
|
||||
next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_STATE_STOPPED:
|
||||
@ -1291,10 +1295,12 @@ static int client_timeout_resend(
|
||||
client->state = DHCP_STATE_REBOOTING;
|
||||
|
||||
client->request_sent = time_now;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_STATE_REBOOTING:
|
||||
case DHCP_STATE_BOUND:
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_STATE_STOPPED:
|
||||
@ -1302,9 +1308,6 @@ static int client_timeout_resend(
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (client->attempt >= TRANSIENT_FAILURE_ATTEMPTS)
|
||||
client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
||||
@ -736,10 +736,3 @@ global:
|
||||
sd_device_has_current_tag;
|
||||
sd_device_set_sysattr_valuef;
|
||||
} LIBSYSTEMD_246;
|
||||
|
||||
LIBSYSTEMD_248 {
|
||||
global:
|
||||
sd_event_source_set_ratelimit;
|
||||
sd_event_source_get_ratelimit;
|
||||
sd_event_source_is_ratelimited;
|
||||
} LIBSYSTEMD_246;
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include "hashmap.h"
|
||||
#include "list.h"
|
||||
#include "prioq.h"
|
||||
#include "ratelimit.h"
|
||||
|
||||
typedef enum EventSourceType {
|
||||
SOURCE_IO,
|
||||
@ -62,7 +61,6 @@ struct sd_event_source {
|
||||
bool dispatching:1;
|
||||
bool floating:1;
|
||||
bool exit_on_failure:1;
|
||||
bool ratelimited:1;
|
||||
|
||||
int64_t priority;
|
||||
unsigned pending_index;
|
||||
@ -74,13 +72,6 @@ struct sd_event_source {
|
||||
|
||||
LIST_FIELDS(sd_event_source, sources);
|
||||
|
||||
RateLimit rate_limit;
|
||||
|
||||
/* These are primarily fields relevant for time event sources, but since any event source can
|
||||
* effectively become one when rate-limited, this is part of the common fields. */
|
||||
unsigned earliest_index;
|
||||
unsigned latest_index;
|
||||
|
||||
union {
|
||||
struct {
|
||||
sd_event_io_handler_t callback;
|
||||
@ -93,6 +84,8 @@ struct sd_event_source {
|
||||
struct {
|
||||
sd_event_time_handler_t callback;
|
||||
usec_t next, accuracy;
|
||||
unsigned earliest_index;
|
||||
unsigned latest_index;
|
||||
} time;
|
||||
struct {
|
||||
sd_event_signal_handler_t callback;
|
||||
|
||||
@ -37,16 +37,6 @@ static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) {
|
||||
s->child.options == WEXITED;
|
||||
}
|
||||
|
||||
static bool event_source_is_online(sd_event_source *s) {
|
||||
assert(s);
|
||||
return s->enabled != SD_EVENT_OFF && !s->ratelimited;
|
||||
}
|
||||
|
||||
static bool event_source_is_offline(sd_event_source *s) {
|
||||
assert(s);
|
||||
return s->enabled == SD_EVENT_OFF || s->ratelimited;
|
||||
}
|
||||
|
||||
static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
|
||||
[SOURCE_IO] = "io",
|
||||
[SOURCE_TIME_REALTIME] = "realtime",
|
||||
@ -65,25 +55,7 @@ static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX]
|
||||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int);
|
||||
|
||||
#define EVENT_SOURCE_IS_TIME(t) \
|
||||
IN_SET((t), \
|
||||
SOURCE_TIME_REALTIME, \
|
||||
SOURCE_TIME_BOOTTIME, \
|
||||
SOURCE_TIME_MONOTONIC, \
|
||||
SOURCE_TIME_REALTIME_ALARM, \
|
||||
SOURCE_TIME_BOOTTIME_ALARM)
|
||||
|
||||
#define EVENT_SOURCE_CAN_RATE_LIMIT(t) \
|
||||
IN_SET((t), \
|
||||
SOURCE_IO, \
|
||||
SOURCE_TIME_REALTIME, \
|
||||
SOURCE_TIME_BOOTTIME, \
|
||||
SOURCE_TIME_MONOTONIC, \
|
||||
SOURCE_TIME_REALTIME_ALARM, \
|
||||
SOURCE_TIME_BOOTTIME_ALARM, \
|
||||
SOURCE_SIGNAL, \
|
||||
SOURCE_DEFER, \
|
||||
SOURCE_INOTIFY)
|
||||
#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM)
|
||||
|
||||
struct sd_event {
|
||||
unsigned n_ref;
|
||||
@ -109,7 +81,7 @@ struct sd_event {
|
||||
Hashmap *signal_data; /* indexed by priority */
|
||||
|
||||
Hashmap *child_sources;
|
||||
unsigned n_online_child_sources;
|
||||
unsigned n_enabled_child_sources;
|
||||
|
||||
Set *post_sources;
|
||||
|
||||
@ -148,7 +120,7 @@ struct sd_event {
|
||||
|
||||
LIST_HEAD(sd_event_source, sources);
|
||||
|
||||
usec_t last_run_usec, last_log_usec;
|
||||
usec_t last_run, last_log;
|
||||
unsigned delays[sizeof(usec_t) * 8];
|
||||
};
|
||||
|
||||
@ -174,11 +146,6 @@ static int pending_prioq_compare(const void *a, const void *b) {
|
||||
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
||||
return 1;
|
||||
|
||||
/* Non rate-limited ones first. */
|
||||
r = CMP(!!x->ratelimited, !!y->ratelimited);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Lower priority values first */
|
||||
r = CMP(x->priority, y->priority);
|
||||
if (r != 0)
|
||||
@ -201,11 +168,6 @@ static int prepare_prioq_compare(const void *a, const void *b) {
|
||||
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
||||
return 1;
|
||||
|
||||
/* Non rate-limited ones first. */
|
||||
r = CMP(!!x->ratelimited, !!y->ratelimited);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
/* Move most recently prepared ones last, so that we can stop
|
||||
* preparing as soon as we hit one that has already been
|
||||
* prepared in the current iteration */
|
||||
@ -217,30 +179,12 @@ static int prepare_prioq_compare(const void *a, const void *b) {
|
||||
return CMP(x->priority, y->priority);
|
||||
}
|
||||
|
||||
static usec_t time_event_source_next(const sd_event_source *s) {
|
||||
assert(s);
|
||||
|
||||
/* We have two kinds of event sources that have elapsation times associated with them: the actual
|
||||
* time based ones and the ones for which a ratelimit can be in effect (where we want to be notified
|
||||
* once the ratelimit time window ends). Let's return the next elapsing time depending on what we are
|
||||
* looking at here. */
|
||||
|
||||
if (s->ratelimited) { /* If rate-limited the next elapsation is when the ratelimit time window ends */
|
||||
assert(s->rate_limit.begin != 0);
|
||||
assert(s->rate_limit.interval != 0);
|
||||
return usec_add(s->rate_limit.begin, s->rate_limit.interval);
|
||||
}
|
||||
|
||||
/* Otherwise this must be a time event source, if not ratelimited */
|
||||
if (EVENT_SOURCE_IS_TIME(s->type))
|
||||
return s->time.next;
|
||||
|
||||
return USEC_INFINITY;
|
||||
}
|
||||
|
||||
static int earliest_time_prioq_compare(const void *a, const void *b) {
|
||||
const sd_event_source *x = a, *y = b;
|
||||
|
||||
assert(EVENT_SOURCE_IS_TIME(x->type));
|
||||
assert(x->type == y->type);
|
||||
|
||||
/* Enabled ones first */
|
||||
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
||||
return -1;
|
||||
@ -254,30 +198,19 @@ static int earliest_time_prioq_compare(const void *a, const void *b) {
|
||||
return 1;
|
||||
|
||||
/* Order by time */
|
||||
return CMP(time_event_source_next(x), time_event_source_next(y));
|
||||
return CMP(x->time.next, y->time.next);
|
||||
}
|
||||
|
||||
static usec_t time_event_source_latest(const sd_event_source *s) {
|
||||
assert(s);
|
||||
|
||||
if (s->ratelimited) { /* For ratelimited stuff the earliest and the latest time shall actually be the
|
||||
* same, as we should avoid adding additional inaccuracy on an inaccuracy time
|
||||
* window */
|
||||
assert(s->rate_limit.begin != 0);
|
||||
assert(s->rate_limit.interval != 0);
|
||||
return usec_add(s->rate_limit.begin, s->rate_limit.interval);
|
||||
}
|
||||
|
||||
/* Must be a time event source, if not ratelimited */
|
||||
if (EVENT_SOURCE_IS_TIME(s->type))
|
||||
return usec_add(s->time.next, s->time.accuracy);
|
||||
|
||||
return USEC_INFINITY;
|
||||
return usec_add(s->time.next, s->time.accuracy);
|
||||
}
|
||||
|
||||
static int latest_time_prioq_compare(const void *a, const void *b) {
|
||||
const sd_event_source *x = a, *y = b;
|
||||
|
||||
assert(EVENT_SOURCE_IS_TIME(x->type));
|
||||
assert(x->type == y->type);
|
||||
|
||||
/* Enabled ones first */
|
||||
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
||||
return -1;
|
||||
@ -447,7 +380,7 @@ static void source_io_unregister(sd_event_source *s) {
|
||||
return;
|
||||
|
||||
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0)
|
||||
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m",
|
||||
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
|
||||
strna(s->description), event_source_type_to_string(s->type));
|
||||
|
||||
s->io.registered = false;
|
||||
@ -489,7 +422,7 @@ static void source_child_pidfd_unregister(sd_event_source *s) {
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0)
|
||||
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m",
|
||||
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
|
||||
strna(s->description), event_source_type_to_string(s->type));
|
||||
|
||||
s->child.registered = false;
|
||||
@ -728,12 +661,12 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig)
|
||||
* and possibly drop the signalfd for it. */
|
||||
|
||||
if (sig == SIGCHLD &&
|
||||
e->n_online_child_sources > 0)
|
||||
e->n_enabled_child_sources > 0)
|
||||
return;
|
||||
|
||||
if (e->signal_sources &&
|
||||
e->signal_sources[sig] &&
|
||||
event_source_is_online(e->signal_sources[sig]))
|
||||
e->signal_sources[sig]->enabled != SD_EVENT_OFF)
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -780,32 +713,13 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) {
|
||||
struct clock_data *d;
|
||||
|
||||
assert(s);
|
||||
assert(EVENT_SOURCE_IS_TIME(s->type));
|
||||
|
||||
/* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy,
|
||||
* pending, enable state. Makes sure the two prioq's are ordered properly again. */
|
||||
|
||||
if (s->ratelimited)
|
||||
d = &s->event->monotonic;
|
||||
else {
|
||||
assert(EVENT_SOURCE_IS_TIME(s->type));
|
||||
assert_se(d = event_get_clock_data(s->event, s->type));
|
||||
}
|
||||
|
||||
prioq_reshuffle(d->earliest, s, &s->earliest_index);
|
||||
prioq_reshuffle(d->latest, s, &s->latest_index);
|
||||
d->needs_rearm = true;
|
||||
}
|
||||
|
||||
static void event_source_time_prioq_remove(
|
||||
sd_event_source *s,
|
||||
struct clock_data *d) {
|
||||
|
||||
assert(s);
|
||||
assert(d);
|
||||
|
||||
prioq_remove(d->earliest, s, &s->earliest_index);
|
||||
prioq_remove(d->latest, s, &s->latest_index);
|
||||
s->earliest_index = s->latest_index = PRIOQ_IDX_NULL;
|
||||
assert_se(d = event_get_clock_data(s->event, s->type));
|
||||
prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
|
||||
prioq_reshuffle(d->latest, s, &s->time.latest_index);
|
||||
d->needs_rearm = true;
|
||||
}
|
||||
|
||||
@ -831,18 +745,17 @@ static void source_disconnect(sd_event_source *s) {
|
||||
case SOURCE_TIME_BOOTTIME:
|
||||
case SOURCE_TIME_MONOTONIC:
|
||||
case SOURCE_TIME_REALTIME_ALARM:
|
||||
case SOURCE_TIME_BOOTTIME_ALARM:
|
||||
/* Only remove this event source from the time event source here if it is not ratelimited. If
|
||||
* it is ratelimited, we'll remove it below, separately. Why? Because the clock used might
|
||||
* differ: ratelimiting always uses CLOCK_MONOTONIC, but timer events might use any clock */
|
||||
case SOURCE_TIME_BOOTTIME_ALARM: {
|
||||
struct clock_data *d;
|
||||
|
||||
if (!s->ratelimited) {
|
||||
struct clock_data *d;
|
||||
assert_se(d = event_get_clock_data(s->event, s->type));
|
||||
event_source_time_prioq_remove(s, d);
|
||||
}
|
||||
d = event_get_clock_data(s->event, s->type);
|
||||
assert(d);
|
||||
|
||||
prioq_remove(d->earliest, s, &s->time.earliest_index);
|
||||
prioq_remove(d->latest, s, &s->time.latest_index);
|
||||
d->needs_rearm = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SOURCE_SIGNAL:
|
||||
if (s->signal.sig > 0) {
|
||||
@ -857,9 +770,9 @@ static void source_disconnect(sd_event_source *s) {
|
||||
|
||||
case SOURCE_CHILD:
|
||||
if (s->child.pid > 0) {
|
||||
if (event_source_is_online(s)) {
|
||||
assert(s->event->n_online_child_sources > 0);
|
||||
s->event->n_online_child_sources--;
|
||||
if (s->enabled != SD_EVENT_OFF) {
|
||||
assert(s->event->n_enabled_child_sources > 0);
|
||||
s->event->n_enabled_child_sources--;
|
||||
}
|
||||
|
||||
(void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid));
|
||||
@ -929,9 +842,6 @@ static void source_disconnect(sd_event_source *s) {
|
||||
if (s->prepare)
|
||||
prioq_remove(s->event->prepare, s, &s->prepare_index);
|
||||
|
||||
if (s->ratelimited)
|
||||
event_source_time_prioq_remove(s, &s->event->monotonic);
|
||||
|
||||
event = TAKE_PTR(s->event);
|
||||
LIST_REMOVE(sources, event->sources, s);
|
||||
event->n_sources--;
|
||||
@ -1178,52 +1088,6 @@ static int time_exit_callback(sd_event_source *s, uint64_t usec, void *userdata)
|
||||
return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
|
||||
}
|
||||
|
||||
static int setup_clock_data(sd_event *e, struct clock_data *d, clockid_t clock) {
|
||||
int r;
|
||||
|
||||
assert(d);
|
||||
|
||||
if (d->fd < 0) {
|
||||
r = event_setup_timer_fd(e, d, clock);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int event_source_time_prioq_put(
|
||||
sd_event_source *s,
|
||||
struct clock_data *d) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(d);
|
||||
|
||||
r = prioq_put(d->earliest, s, &s->earliest_index);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = prioq_put(d->latest, s, &s->latest_index);
|
||||
if (r < 0) {
|
||||
assert_se(prioq_remove(d->earliest, s, &s->earliest_index) > 0);
|
||||
s->earliest_index = PRIOQ_IDX_NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
d->needs_rearm = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_add_time(
|
||||
sd_event *e,
|
||||
sd_event_source **ret,
|
||||
@ -1254,12 +1118,23 @@ _public_ int sd_event_add_time(
|
||||
if (!callback)
|
||||
callback = time_exit_callback;
|
||||
|
||||
assert_se(d = event_get_clock_data(e, type));
|
||||
d = event_get_clock_data(e, type);
|
||||
assert(d);
|
||||
|
||||
r = setup_clock_data(e, d, clock);
|
||||
r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (d->fd < 0) {
|
||||
r = event_setup_timer_fd(e, d, clock);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
s = source_new(e, !ret, type);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
@ -1267,11 +1142,17 @@ _public_ int sd_event_add_time(
|
||||
s->time.next = usec;
|
||||
s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy;
|
||||
s->time.callback = callback;
|
||||
s->earliest_index = s->latest_index = PRIOQ_IDX_NULL;
|
||||
s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL;
|
||||
s->userdata = userdata;
|
||||
s->enabled = SD_EVENT_ONESHOT;
|
||||
|
||||
r = event_source_time_prioq_put(s, d);
|
||||
d->needs_rearm = true;
|
||||
|
||||
r = prioq_put(d->earliest, s, &s->time.earliest_index);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = prioq_put(d->latest, s, &s->time.latest_index);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1404,7 +1285,7 @@ _public_ int sd_event_add_child(
|
||||
if (!callback)
|
||||
callback = child_exit_callback;
|
||||
|
||||
if (e->n_online_child_sources == 0) {
|
||||
if (e->n_enabled_child_sources == 0) {
|
||||
/* Caller must block SIGCHLD before using us to watch children, even if pidfd is available,
|
||||
* for compatibility with pre-pidfd and because we don't want the reap the child processes
|
||||
* ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to
|
||||
@ -1469,7 +1350,7 @@ _public_ int sd_event_add_child(
|
||||
e->need_process_child = true;
|
||||
}
|
||||
|
||||
e->n_online_child_sources++;
|
||||
e->n_enabled_child_sources++;
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
@ -1501,7 +1382,7 @@ _public_ int sd_event_add_child_pidfd(
|
||||
if (!callback)
|
||||
callback = child_exit_callback;
|
||||
|
||||
if (e->n_online_child_sources == 0) {
|
||||
if (e->n_enabled_child_sources == 0) {
|
||||
r = signal_is_blocked(SIGCHLD);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1551,7 +1432,7 @@ _public_ int sd_event_add_child_pidfd(
|
||||
e->need_process_child = true;
|
||||
}
|
||||
|
||||
e->n_online_child_sources++;
|
||||
e->n_enabled_child_sources++;
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
@ -2137,7 +2018,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
|
||||
if (s->io.fd == fd)
|
||||
return 0;
|
||||
|
||||
if (event_source_is_offline(s)) {
|
||||
if (s->enabled == SD_EVENT_OFF) {
|
||||
s->io.fd = fd;
|
||||
s->io.registered = false;
|
||||
} else {
|
||||
@ -2204,7 +2085,7 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (event_source_is_online(s)) {
|
||||
if (s->enabled != SD_EVENT_OFF) {
|
||||
r = source_io_register(s, s->enabled, events);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -2307,7 +2188,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority)
|
||||
|
||||
event_gc_inode_data(s->event, old_inode_data);
|
||||
|
||||
} else if (s->type == SOURCE_SIGNAL && event_source_is_online(s)) {
|
||||
} else if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) {
|
||||
struct signal_data *old, *d;
|
||||
|
||||
/* Move us from the signalfd belonging to the old
|
||||
@ -2344,39 +2225,29 @@ fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) {
|
||||
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||
|
||||
if (ret)
|
||||
*ret = s->enabled;
|
||||
|
||||
if (m)
|
||||
*m = s->enabled;
|
||||
return s->enabled != SD_EVENT_OFF;
|
||||
}
|
||||
|
||||
static int event_source_offline(
|
||||
sd_event_source *s,
|
||||
int enabled,
|
||||
bool ratelimited) {
|
||||
|
||||
bool was_offline;
|
||||
static int event_source_disable(sd_event_source *s) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(enabled == SD_EVENT_OFF || ratelimited);
|
||||
assert(s->enabled != SD_EVENT_OFF);
|
||||
|
||||
/* Unset the pending flag when this event source is disabled */
|
||||
if (s->enabled != SD_EVENT_OFF &&
|
||||
enabled == SD_EVENT_OFF &&
|
||||
!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||
r = source_set_pending(s, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
was_offline = event_source_is_offline(s);
|
||||
s->enabled = enabled;
|
||||
s->ratelimited = ratelimited;
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
|
||||
switch (s->type) {
|
||||
|
||||
@ -2397,10 +2268,8 @@ static int event_source_offline(
|
||||
break;
|
||||
|
||||
case SOURCE_CHILD:
|
||||
if (!was_offline) {
|
||||
assert(s->event->n_online_child_sources > 0);
|
||||
s->event->n_online_child_sources--;
|
||||
}
|
||||
assert(s->event->n_enabled_child_sources > 0);
|
||||
s->event->n_enabled_child_sources--;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
source_child_pidfd_unregister(s);
|
||||
@ -2421,42 +2290,26 @@ static int event_source_offline(
|
||||
assert_not_reached("Wut? I shouldn't exist.");
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int event_source_online(
|
||||
sd_event_source *s,
|
||||
int enabled,
|
||||
bool ratelimited) {
|
||||
|
||||
bool was_online;
|
||||
static int event_source_enable(sd_event_source *s, int enable) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(enabled != SD_EVENT_OFF || !ratelimited);
|
||||
assert(IN_SET(enable, SD_EVENT_ON, SD_EVENT_ONESHOT));
|
||||
assert(s->enabled == SD_EVENT_OFF);
|
||||
|
||||
/* Unset the pending flag when this event source is enabled */
|
||||
if (s->enabled == SD_EVENT_OFF &&
|
||||
enabled != SD_EVENT_OFF &&
|
||||
!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||
r = source_set_pending(s, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Are we really ready for onlining? */
|
||||
if (enabled == SD_EVENT_OFF || ratelimited) {
|
||||
/* Nope, we are not ready for onlining, then just update the precise state and exit */
|
||||
s->enabled = enabled;
|
||||
s->ratelimited = ratelimited;
|
||||
return 0;
|
||||
}
|
||||
|
||||
was_online = event_source_is_online(s);
|
||||
|
||||
switch (s->type) {
|
||||
case SOURCE_IO:
|
||||
r = source_io_register(s, enabled, s->io.events);
|
||||
r = source_io_register(s, enable, s->io.events);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
@ -2474,7 +2327,7 @@ static int event_source_online(
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* yes, we have pidfd */
|
||||
|
||||
r = source_child_pidfd_register(s, enabled);
|
||||
r = source_child_pidfd_register(s, enable);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
@ -2487,8 +2340,8 @@ static int event_source_online(
|
||||
}
|
||||
}
|
||||
|
||||
if (!was_online)
|
||||
s->event->n_online_child_sources++;
|
||||
s->event->n_enabled_child_sources++;
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_TIME_REALTIME:
|
||||
@ -2506,8 +2359,7 @@ static int event_source_online(
|
||||
assert_not_reached("Wut? I shouldn't exist.");
|
||||
}
|
||||
|
||||
s->enabled = enabled;
|
||||
s->ratelimited = ratelimited;
|
||||
s->enabled = enable;
|
||||
|
||||
/* Non-failing operations below */
|
||||
switch (s->type) {
|
||||
@ -2527,7 +2379,7 @@ static int event_source_online(
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
||||
@ -2545,7 +2397,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
||||
return 0;
|
||||
|
||||
if (m == SD_EVENT_OFF)
|
||||
r = event_source_offline(s, m, s->ratelimited);
|
||||
r = event_source_disable(s);
|
||||
else {
|
||||
if (s->enabled != SD_EVENT_OFF) {
|
||||
/* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the
|
||||
@ -2554,7 +2406,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = event_source_online(s, m, s->ratelimited);
|
||||
r = event_source_enable(s, m);
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -2811,96 +2663,6 @@ _public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int event_source_enter_ratelimited(sd_event_source *s) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
/* When an event source becomes ratelimited, we place it in the CLOCK_MONOTONIC priority queue, with
|
||||
* the end of the rate limit time window, much as if it was a timer event source. */
|
||||
|
||||
if (s->ratelimited)
|
||||
return 0; /* Already ratelimited, this is a NOP hence */
|
||||
|
||||
/* Make sure we can install a CLOCK_MONOTONIC event further down. */
|
||||
r = setup_clock_data(s->event, &s->event->monotonic, CLOCK_MONOTONIC);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Timer event sources are already using the earliest/latest queues for the timer scheduling. Let's
|
||||
* first remove them from the prioq appropriate for their own clock, so that we can use the prioq
|
||||
* fields of the event source then for adding it to the CLOCK_MONOTONIC prioq instead. */
|
||||
if (EVENT_SOURCE_IS_TIME(s->type))
|
||||
event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type));
|
||||
|
||||
/* Now, let's add the event source to the monotonic clock instead */
|
||||
r = event_source_time_prioq_put(s, &s->event->monotonic);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
/* And let's take the event source officially offline */
|
||||
r = event_source_offline(s, s->enabled, /* ratelimited= */ true);
|
||||
if (r < 0) {
|
||||
event_source_time_prioq_remove(s, &s->event->monotonic);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
event_source_pp_prioq_reshuffle(s);
|
||||
|
||||
log_debug("Event source %p (%s) entered rate limit state.", s, strna(s->description));
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
/* Reinstall time event sources in the priority queue as before. This shouldn't fail, since the queue
|
||||
* space for it should already be allocated. */
|
||||
if (EVENT_SOURCE_IS_TIME(s->type))
|
||||
assert_se(event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)) >= 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int event_source_leave_ratelimit(sd_event_source *s) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
if (!s->ratelimited)
|
||||
return 0;
|
||||
|
||||
/* Let's take the event source out of the monotonic prioq first. */
|
||||
event_source_time_prioq_remove(s, &s->event->monotonic);
|
||||
|
||||
/* Let's then add the event source to its native clock prioq again — if this is a timer event source */
|
||||
if (EVENT_SOURCE_IS_TIME(s->type)) {
|
||||
r = event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Let's try to take it online again. */
|
||||
r = event_source_online(s, s->enabled, /* ratelimited= */ false);
|
||||
if (r < 0) {
|
||||
/* Do something roughly sensible when this failed: undo the two prioq ops above */
|
||||
if (EVENT_SOURCE_IS_TIME(s->type))
|
||||
event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type));
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
event_source_pp_prioq_reshuffle(s);
|
||||
ratelimit_reset(&s->rate_limit);
|
||||
|
||||
log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description));
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
/* Do something somewhat reasonable when we cannot move an event sources out of ratelimited mode:
|
||||
* simply put it back in it, maybe we can then process it more successfully next iteration. */
|
||||
assert_se(event_source_time_prioq_put(s, &s->event->monotonic) >= 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) {
|
||||
usec_t c;
|
||||
assert(e);
|
||||
@ -2998,7 +2760,7 @@ static int event_arm_timer(
|
||||
d->needs_rearm = false;
|
||||
|
||||
a = prioq_peek(d->earliest);
|
||||
if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) {
|
||||
if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) {
|
||||
|
||||
if (d->fd < 0)
|
||||
return 0;
|
||||
@ -3017,7 +2779,7 @@ static int event_arm_timer(
|
||||
b = prioq_peek(d->latest);
|
||||
assert_se(b && b->enabled != SD_EVENT_OFF);
|
||||
|
||||
t = sleep_between(e, time_event_source_next(a), time_event_source_latest(b));
|
||||
t = sleep_between(e, a->time.next, time_event_source_latest(b));
|
||||
if (d->next == t)
|
||||
return 0;
|
||||
|
||||
@ -3095,22 +2857,10 @@ static int process_timer(
|
||||
|
||||
for (;;) {
|
||||
s = prioq_peek(d->earliest);
|
||||
if (!s || time_event_source_next(s) > n)
|
||||
break;
|
||||
|
||||
if (s->ratelimited) {
|
||||
/* This is an event sources whose ratelimit window has ended. Let's turn it on
|
||||
* again. */
|
||||
assert(s->ratelimited);
|
||||
|
||||
r = event_source_leave_ratelimit(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s->enabled == SD_EVENT_OFF || s->pending)
|
||||
if (!s ||
|
||||
s->time.next > n ||
|
||||
s->enabled == SD_EVENT_OFF ||
|
||||
s->pending)
|
||||
break;
|
||||
|
||||
r = source_set_pending(s, true);
|
||||
@ -3155,7 +2905,7 @@ static int process_child(sd_event *e) {
|
||||
if (s->pending)
|
||||
continue;
|
||||
|
||||
if (event_source_is_offline(s))
|
||||
if (s->enabled == SD_EVENT_OFF)
|
||||
continue;
|
||||
|
||||
if (s->child.exited)
|
||||
@ -3202,7 +2952,7 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
|
||||
if (s->pending)
|
||||
return 0;
|
||||
|
||||
if (event_source_is_offline(s))
|
||||
if (s->enabled == SD_EVENT_OFF)
|
||||
return 0;
|
||||
|
||||
if (!EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
@ -3362,7 +3112,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) {
|
||||
|
||||
LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) {
|
||||
|
||||
if (event_source_is_offline(s))
|
||||
if (s->enabled == SD_EVENT_OFF)
|
||||
continue;
|
||||
|
||||
r = source_set_pending(s, true);
|
||||
@ -3398,7 +3148,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) {
|
||||
* sources if IN_IGNORED or IN_UNMOUNT is set. */
|
||||
LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) {
|
||||
|
||||
if (event_source_is_offline(s))
|
||||
if (s->enabled == SD_EVENT_OFF)
|
||||
continue;
|
||||
|
||||
if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 &&
|
||||
@ -3452,16 +3202,6 @@ static int source_dispatch(sd_event_source *s) {
|
||||
* callback might have invalidated/disconnected the event source. */
|
||||
saved_event = sd_event_ref(s->event);
|
||||
|
||||
/* Check if we hit the ratelimit for this event source, if so, let's disable it. */
|
||||
assert(!s->ratelimited);
|
||||
if (!ratelimit_below(&s->rate_limit)) {
|
||||
r = event_source_enter_ratelimited(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||
r = source_set_pending(s, false);
|
||||
if (r < 0)
|
||||
@ -3475,7 +3215,7 @@ static int source_dispatch(sd_event_source *s) {
|
||||
* post sources as pending */
|
||||
|
||||
SET_FOREACH(z, s->event->post_sources) {
|
||||
if (event_source_is_offline(z))
|
||||
if (z->enabled == SD_EVENT_OFF)
|
||||
continue;
|
||||
|
||||
r = source_set_pending(z, true);
|
||||
@ -3595,7 +3335,7 @@ static int event_prepare(sd_event *e) {
|
||||
sd_event_source *s;
|
||||
|
||||
s = prioq_peek(e->prepare);
|
||||
if (!s || s->prepare_iteration == e->iteration || event_source_is_offline(s))
|
||||
if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF)
|
||||
break;
|
||||
|
||||
s->prepare_iteration = e->iteration;
|
||||
@ -3630,17 +3370,18 @@ static int event_prepare(sd_event *e) {
|
||||
|
||||
static int dispatch_exit(sd_event *e) {
|
||||
sd_event_source *p;
|
||||
_cleanup_(sd_event_unrefp) sd_event *ref = NULL;
|
||||
int r;
|
||||
|
||||
assert(e);
|
||||
|
||||
p = prioq_peek(e->exit);
|
||||
if (!p || event_source_is_offline(p)) {
|
||||
if (!p || p->enabled == SD_EVENT_OFF) {
|
||||
e->state = SD_EVENT_FINISHED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
|
||||
ref = sd_event_ref(e);
|
||||
e->iteration++;
|
||||
e->state = SD_EVENT_EXITING;
|
||||
r = source_dispatch(p);
|
||||
@ -3657,7 +3398,7 @@ static sd_event_source* event_next_pending(sd_event *e) {
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (event_source_is_offline(p))
|
||||
if (p->enabled == SD_EVENT_OFF)
|
||||
return NULL;
|
||||
|
||||
return p;
|
||||
@ -3736,9 +3477,6 @@ _public_ int sd_event_prepare(sd_event *e) {
|
||||
* syscalls */
|
||||
assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO);
|
||||
|
||||
/* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */
|
||||
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
|
||||
|
||||
if (e->exit_requested)
|
||||
goto pending;
|
||||
|
||||
@ -3944,8 +3682,9 @@ _public_ int sd_event_dispatch(sd_event *e) {
|
||||
|
||||
p = event_next_pending(e);
|
||||
if (p) {
|
||||
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
|
||||
_cleanup_(sd_event_unrefp) sd_event *ref = NULL;
|
||||
|
||||
ref = sd_event_ref(e);
|
||||
e->state = SD_EVENT_RUNNING;
|
||||
r = source_dispatch(p);
|
||||
e->state = SD_EVENT_INITIAL;
|
||||
@ -3979,32 +3718,29 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
|
||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
|
||||
|
||||
if (e->profile_delays && e->last_run_usec != 0) {
|
||||
if (e->profile_delays && e->last_run) {
|
||||
usec_t this_run;
|
||||
unsigned l;
|
||||
|
||||
this_run = now(CLOCK_MONOTONIC);
|
||||
|
||||
l = u64log2(this_run - e->last_run_usec);
|
||||
l = u64log2(this_run - e->last_run);
|
||||
assert(l < ELEMENTSOF(e->delays));
|
||||
e->delays[l]++;
|
||||
|
||||
if (this_run - e->last_log_usec >= 5*USEC_PER_SEC) {
|
||||
if (this_run - e->last_log >= 5*USEC_PER_SEC) {
|
||||
event_log_delays(e);
|
||||
e->last_log_usec = this_run;
|
||||
e->last_log = this_run;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */
|
||||
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
|
||||
|
||||
r = sd_event_prepare(e);
|
||||
if (r == 0)
|
||||
/* There was nothing? Then wait... */
|
||||
r = sd_event_wait(e, timeout);
|
||||
|
||||
if (e->profile_delays)
|
||||
e->last_run_usec = now(CLOCK_MONOTONIC);
|
||||
e->last_run = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (r > 0) {
|
||||
/* There's something now, then let's dispatch it */
|
||||
@ -4019,6 +3755,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
|
||||
}
|
||||
|
||||
_public_ int sd_event_loop(sd_event *e) {
|
||||
_cleanup_(sd_event_unrefp) sd_event *ref = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
@ -4026,7 +3763,7 @@ _public_ int sd_event_loop(sd_event *e) {
|
||||
assert_return(!event_pid_changed(e), -ECHILD);
|
||||
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
|
||||
|
||||
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
|
||||
ref = sd_event_ref(e);
|
||||
|
||||
while (e->state != SD_EVENT_FINISHED) {
|
||||
r = sd_event_run(e, (uint64_t) -1);
|
||||
@ -4271,53 +4008,3 @@ _public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) {
|
||||
s->exit_on_failure = b;
|
||||
return 1;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval, unsigned burst) {
|
||||
int r;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
|
||||
/* Turning on ratelimiting on event source types that don't support it, is a loggable offense. Doing
|
||||
* so is a programming error. */
|
||||
assert_return(EVENT_SOURCE_CAN_RATE_LIMIT(s->type), -EDOM);
|
||||
|
||||
/* When ratelimiting is configured we'll always reset the rate limit state first and start fresh,
|
||||
* non-ratelimited. */
|
||||
r = event_source_leave_ratelimit(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
s->rate_limit = (RateLimit) { interval, burst };
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) {
|
||||
assert_return(s, -EINVAL);
|
||||
|
||||
/* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence
|
||||
* don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */
|
||||
if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type))
|
||||
return -EDOM;
|
||||
|
||||
if (!ratelimit_configured(&s->rate_limit))
|
||||
return -ENOEXEC;
|
||||
|
||||
if (ret_interval)
|
||||
*ret_interval = s->rate_limit.interval;
|
||||
if (ret_burst)
|
||||
*ret_burst = s->rate_limit.burst;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_is_ratelimited(sd_event_source *s) {
|
||||
assert_return(s, -EINVAL);
|
||||
|
||||
if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type))
|
||||
return false;
|
||||
|
||||
if (!ratelimit_configured(&s->rate_limit))
|
||||
return false;
|
||||
|
||||
return s->ratelimited;
|
||||
}
|
||||
|
||||
@ -589,100 +589,8 @@ static void test_pidfd(void) {
|
||||
sd_event_unref(e);
|
||||
}
|
||||
|
||||
static int ratelimit_io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
unsigned *c = (unsigned*) userdata;
|
||||
*c += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ratelimit_time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
int r;
|
||||
|
||||
r = sd_event_source_set_enabled(s, SD_EVENT_ON);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to turn on notify event source: %m");
|
||||
|
||||
r = sd_event_source_set_time(s, usec + 1000);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to restart watchdog event source: %m");
|
||||
|
||||
unsigned *c = (unsigned*) userdata;
|
||||
*c += 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_ratelimit(void) {
|
||||
_cleanup_close_pair_ int p[2] = {-1, -1};
|
||||
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
|
||||
uint64_t interval;
|
||||
unsigned count, burst;
|
||||
|
||||
assert_se(sd_event_default(&e) >= 0);
|
||||
assert_se(pipe2(p, O_CLOEXEC|O_NONBLOCK) >= 0);
|
||||
|
||||
assert_se(sd_event_add_io(e, &s, p[0], EPOLLIN, ratelimit_io_handler, &count) >= 0);
|
||||
assert_se(sd_event_source_set_description(s, "test-ratelimit-io") >= 0);
|
||||
assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 5) >= 0);
|
||||
assert_se(sd_event_source_get_ratelimit(s, &interval, &burst) >= 0);
|
||||
assert_se(interval == 1 * USEC_PER_SEC && burst == 5);
|
||||
|
||||
assert_se(write(p[1], "1", 1) == 1);
|
||||
|
||||
count = 0;
|
||||
for (unsigned i = 0; i < 10; i++) {
|
||||
log_debug("slow loop iteration %u", i);
|
||||
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
|
||||
assert_se(usleep(250 * USEC_PER_MSEC) >= 0);
|
||||
}
|
||||
|
||||
assert_se(sd_event_source_is_ratelimited(s) == 0);
|
||||
assert_se(count == 10);
|
||||
log_info("ratelimit_io_handler: called %d times, event source not ratelimited", count);
|
||||
|
||||
assert_se(sd_event_source_set_ratelimit(s, 0, 0) >= 0);
|
||||
assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 5) >= 0);
|
||||
|
||||
count = 0;
|
||||
for (unsigned i = 0; i < 10; i++) {
|
||||
log_debug("fast event loop iteration %u", i);
|
||||
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
|
||||
assert_se(usleep(10) >= 0);
|
||||
}
|
||||
log_info("ratelimit_io_handler: called %d times, event source got ratelimited", count);
|
||||
assert_se(count < 10);
|
||||
|
||||
s = sd_event_source_unref(s);
|
||||
safe_close_pair(p);
|
||||
|
||||
count = 0;
|
||||
assert_se(sd_event_add_time_relative(e, &s, CLOCK_MONOTONIC, 1000, 1, ratelimit_time_handler, &count) >= 0);
|
||||
assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) == 0);
|
||||
|
||||
do {
|
||||
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
|
||||
} while (!sd_event_source_is_ratelimited(s));
|
||||
|
||||
log_info("ratelimit_time_handler: called %d times, event source got ratelimited", count);
|
||||
assert_se(count == 10);
|
||||
|
||||
/* In order to get rid of active rate limit client needs to disable it explicitely */
|
||||
assert_se(sd_event_source_set_ratelimit(s, 0, 0) >= 0);
|
||||
assert_se(!sd_event_source_is_ratelimited(s));
|
||||
|
||||
assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) >= 0);
|
||||
|
||||
do {
|
||||
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
|
||||
} while (!sd_event_source_is_ratelimited(s));
|
||||
|
||||
log_info("ratelimit_time_handler: called 10 more times, event source got ratelimited");
|
||||
assert_se(count == 20);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
test_setup_logging(LOG_INFO);
|
||||
|
||||
test_basic(true); /* test with pidfd */
|
||||
test_basic(false); /* test without pidfd */
|
||||
@ -695,7 +603,5 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
test_pidfd();
|
||||
|
||||
test_ratelimit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -986,7 +986,7 @@ static int macsec_read_key_file(NetDev *netdev, SecurityAssociation *sa) {
|
||||
(void) warn_file_is_world_accessible(sa->key_file, NULL, NULL, 0);
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, sa->key_file, UINT64_MAX, SIZE_MAX,
|
||||
AT_FDCWD, sa->key_file,
|
||||
READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL, (char **) &key, &key_len);
|
||||
if (r < 0)
|
||||
|
||||
@ -869,7 +869,7 @@ static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_
|
||||
(void) warn_file_is_world_accessible(filename, NULL, NULL, 0);
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, filename, UINT64_MAX, SIZE_MAX,
|
||||
AT_FDCWD, filename,
|
||||
READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL, &key, &key_len);
|
||||
if (r < 0)
|
||||
|
||||
@ -62,9 +62,11 @@ static struct DUID fallback_duid = { .type = DUID_TYPE_EN };
|
||||
DUID* link_get_duid(Link *link) {
|
||||
if (link->network->duid.type != _DUID_TYPE_INVALID)
|
||||
return &link->network->duid;
|
||||
else if (link->hw_addr.length == 0 && IN_SET(link->manager->duid.type, DUID_TYPE_LLT, DUID_TYPE_LL))
|
||||
/* Fallback to DUID that works without MAC address.
|
||||
* This is useful for tunnel devices without MAC address. */
|
||||
else if (link->hw_addr.length == 0 &&
|
||||
(link->manager->duid.type == DUID_TYPE_LLT ||
|
||||
link->manager->duid.type == DUID_TYPE_LL))
|
||||
/* Fallback to DUID that works without mac addresses.
|
||||
* This is useful for tunnel devices without mac address. */
|
||||
return &fallback_duid;
|
||||
else
|
||||
return &link->manager->duid;
|
||||
|
||||
@ -70,10 +70,6 @@ static void dhcp4_check_ready(Link *link) {
|
||||
return;
|
||||
}
|
||||
|
||||
r = sd_ipv4ll_stop(link->ipv4ll);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to drop IPv4 link-local address, ignoring: %m");
|
||||
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
@ -1052,7 +1048,10 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
|
||||
|
||||
switch (event) {
|
||||
case SD_DHCP_CLIENT_EVENT_STOP:
|
||||
if (link->ipv4ll) {
|
||||
|
||||
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4)) {
|
||||
assert(link->ipv4ll);
|
||||
|
||||
log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address");
|
||||
|
||||
r = sd_ipv4ll_start(link->ipv4ll);
|
||||
@ -1137,17 +1136,6 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
|
||||
return -ENOMSG;
|
||||
}
|
||||
break;
|
||||
|
||||
case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE:
|
||||
if (link->ipv4ll && !sd_ipv4ll_is_running(link->ipv4ll)) {
|
||||
log_link_debug(link, "Problems acquiring DHCP lease, acquiring IPv4 link-local address");
|
||||
|
||||
r = sd_ipv4ll_start(link->ipv4ll);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (event < 0)
|
||||
log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
|
||||
|
||||
@ -148,7 +148,7 @@ int ipv4ll_configure(Link *link) {
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!link_ipv4ll_enabled(link))
|
||||
if (!link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4))
|
||||
return 0;
|
||||
|
||||
if (!link->ipv4ll) {
|
||||
|
||||
@ -55,8 +55,9 @@
|
||||
#include "util.h"
|
||||
#include "vrf.h"
|
||||
|
||||
bool link_ipv4ll_enabled(Link *link) {
|
||||
bool link_ipv4ll_enabled(Link *link, AddressFamily mask) {
|
||||
assert(link);
|
||||
assert((mask & ~(ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) == 0);
|
||||
|
||||
if (link->flags & IFF_LOOPBACK)
|
||||
return false;
|
||||
@ -79,7 +80,7 @@ bool link_ipv4ll_enabled(Link *link) {
|
||||
if (link->network->bond)
|
||||
return false;
|
||||
|
||||
return link->network->link_local & ADDRESS_FAMILY_IPV4;
|
||||
return link->network->link_local & mask;
|
||||
}
|
||||
|
||||
bool link_ipv6ll_enabled(Link *link) {
|
||||
@ -733,51 +734,77 @@ void link_check_ready(Link *link) {
|
||||
if (link->state == LINK_STATE_CONFIGURED)
|
||||
return;
|
||||
|
||||
if (link->state != LINK_STATE_CONFIGURING)
|
||||
return (void) log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
|
||||
if (link->state != LINK_STATE_CONFIGURING) {
|
||||
log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->network)
|
||||
return;
|
||||
|
||||
if (!link->addresses_configured)
|
||||
return (void) log_link_debug(link, "%s(): static addresses are not configured.", __func__);
|
||||
if (!link->addresses_configured) {
|
||||
log_link_debug(link, "%s(): static addresses are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->neighbors_configured)
|
||||
return (void) log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
|
||||
if (!link->neighbors_configured) {
|
||||
log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
SET_FOREACH(a, link->addresses)
|
||||
if (!address_is_ready(a)) {
|
||||
_cleanup_free_ char *str = NULL;
|
||||
|
||||
(void) in_addr_to_string(a->family, &a->in_addr, &str);
|
||||
return (void) log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen);
|
||||
log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->static_routes_configured)
|
||||
return (void) log_link_debug(link, "%s(): static routes are not configured.", __func__);
|
||||
if (!link->static_routes_configured) {
|
||||
log_link_debug(link, "%s(): static routes are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->static_nexthops_configured)
|
||||
return (void) log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
|
||||
if (!link->static_nexthops_configured) {
|
||||
log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->routing_policy_rules_configured)
|
||||
return (void) log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
|
||||
if (!link->routing_policy_rules_configured) {
|
||||
log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->tc_configured)
|
||||
return (void) log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
|
||||
if (!link->tc_configured) {
|
||||
log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->sr_iov_configured)
|
||||
return (void) log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
|
||||
if (!link->sr_iov_configured) {
|
||||
log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!link->bridge_mdb_configured)
|
||||
return (void) log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__);
|
||||
if (!link->bridge_mdb_configured) {
|
||||
log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (link_has_carrier(link) || !link->network->configure_without_carrier) {
|
||||
bool has_ndisc_address = false;
|
||||
NDiscAddress *n;
|
||||
|
||||
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address_configured) {
|
||||
log_link_debug(link, "%s(): IPv4LL is not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (link_ipv6ll_enabled(link) &&
|
||||
in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address))
|
||||
return (void) log_link_debug(link, "%s(): IPv6LL is not configured.", __func__);
|
||||
in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) {
|
||||
log_link_debug(link, "%s(): IPv6LL is not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
SET_FOREACH(n, link->ndisc_addresses)
|
||||
if (!n->marked) {
|
||||
@ -785,26 +812,28 @@ void link_check_ready(Link *link) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_ipv4ll_enabled(link)) &&
|
||||
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) &&
|
||||
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
|
||||
!link->ipv4ll_address_configured)
|
||||
/* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
|
||||
return (void) log_link_debug(link, "%s(): DHCP4, DHCP6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
|
||||
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
|
||||
log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no dynamic address is assigned yet.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
|
||||
link_ipv6_accept_ra_enabled(link) || link_ipv4ll_enabled(link)) {
|
||||
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) || link_ipv6_accept_ra_enabled(link)) {
|
||||
if (!link->dhcp4_configured &&
|
||||
!(link->dhcp6_address_configured && link->dhcp6_route_configured) &&
|
||||
!(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) &&
|
||||
!(link->ndisc_addresses_configured && link->ndisc_routes_configured) &&
|
||||
!link->ipv4ll_address_configured)
|
||||
/* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */
|
||||
return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
||||
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
|
||||
/* When DHCP or RA is enabled, at least one protocol must provide an address, or
|
||||
* an IPv4ll fallback address must be configured. */
|
||||
log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
log_link_debug(link, "%s(): dhcp4:%s ipv4ll:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s",
|
||||
log_link_debug(link, "%s(): dhcp4:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s",
|
||||
__func__,
|
||||
yes_no(link->dhcp4_configured),
|
||||
yes_no(link->ipv4ll_address_configured),
|
||||
yes_no(link->dhcp6_address_configured),
|
||||
yes_no(link->dhcp6_route_configured),
|
||||
yes_no(link->dhcp6_pd_address_configured),
|
||||
@ -815,6 +844,8 @@ void link_check_ready(Link *link) {
|
||||
}
|
||||
|
||||
link_enter_configured(link);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int link_set_static_configs(Link *link) {
|
||||
@ -1199,19 +1230,22 @@ static int link_acquire_ipv4_conf(Link *link) {
|
||||
assert(link->manager);
|
||||
assert(link->manager->event);
|
||||
|
||||
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4)) {
|
||||
assert(link->ipv4ll);
|
||||
|
||||
log_link_debug(link, "Acquiring IPv4 link-local address");
|
||||
|
||||
r = sd_ipv4ll_start(link->ipv4ll);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
|
||||
}
|
||||
|
||||
if (link->dhcp_client) {
|
||||
log_link_debug(link, "Acquiring DHCPv4 lease");
|
||||
|
||||
r = sd_dhcp_client_start(link->dhcp_client);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
|
||||
|
||||
} else if (link->ipv4ll) {
|
||||
log_link_debug(link, "Acquiring IPv4 link-local address");
|
||||
|
||||
r = sd_ipv4ll_start(link->ipv4ll);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -231,7 +231,7 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address);
|
||||
|
||||
int link_set_mtu(Link *link, uint32_t mtu);
|
||||
|
||||
bool link_ipv4ll_enabled(Link *link);
|
||||
bool link_ipv4ll_enabled(Link *link, AddressFamily mask);
|
||||
|
||||
int link_stop_engines(Link *link, bool may_keep_dhcp);
|
||||
|
||||
|
||||
@ -210,6 +210,13 @@ int network_verify(Network *network) {
|
||||
if (network->link_local < 0)
|
||||
network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
|
||||
|
||||
if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
|
||||
!FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
|
||||
log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
|
||||
"Disabling the fallback assignment.", network->filename);
|
||||
SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
|
||||
}
|
||||
|
||||
/* IPMasquerade=yes implies IPForward=yes */
|
||||
if (network->ip_masquerade)
|
||||
network->ip_forward |= ADDRESS_FAMILY_IPV4;
|
||||
|
||||
@ -15,6 +15,15 @@ static const char* const address_family_table[_ADDRESS_FAMILY_MAX] = {
|
||||
[ADDRESS_FAMILY_IPV6] = "ipv6",
|
||||
};
|
||||
|
||||
static const char* const link_local_address_family_table[_ADDRESS_FAMILY_MAX] = {
|
||||
[ADDRESS_FAMILY_NO] = "no",
|
||||
[ADDRESS_FAMILY_YES] = "yes",
|
||||
[ADDRESS_FAMILY_IPV4] = "ipv4",
|
||||
[ADDRESS_FAMILY_IPV6] = "ipv6",
|
||||
[ADDRESS_FAMILY_FALLBACK] = "fallback",
|
||||
[ADDRESS_FAMILY_FALLBACK_IPV4] = "ipv4-fallback",
|
||||
};
|
||||
|
||||
static const char* const routing_policy_rule_address_family_table[_ADDRESS_FAMILY_MAX] = {
|
||||
[ADDRESS_FAMILY_YES] = "both",
|
||||
[ADDRESS_FAMILY_IPV4] = "ipv4",
|
||||
@ -38,15 +47,7 @@ static const char* const dhcp_lease_server_type_table[_SD_DHCP_LEASE_SERVER_TYPE
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(address_family, AddressFamily, ADDRESS_FAMILY_YES);
|
||||
|
||||
AddressFamily link_local_address_family_from_string(const char *s) {
|
||||
if (streq_ptr(s, "fallback")) /* compat name */
|
||||
return ADDRESS_FAMILY_YES;
|
||||
if (streq_ptr(s, "fallback-ipv4")) /* compat name */
|
||||
return ADDRESS_FAMILY_IPV4;
|
||||
return address_family_from_string(s);
|
||||
}
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(link_local_address_family, AddressFamily, ADDRESS_FAMILY_YES);
|
||||
DEFINE_STRING_TABLE_LOOKUP(routing_policy_rule_address_family, AddressFamily);
|
||||
DEFINE_STRING_TABLE_LOOKUP(duplicate_address_detection_address_family, AddressFamily);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_link_local_address_family, link_local_address_family,
|
||||
|
||||
@ -16,6 +16,8 @@ typedef enum AddressFamily {
|
||||
ADDRESS_FAMILY_IPV4 = 1 << 0,
|
||||
ADDRESS_FAMILY_IPV6 = 1 << 1,
|
||||
ADDRESS_FAMILY_YES = ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6,
|
||||
ADDRESS_FAMILY_FALLBACK_IPV4 = 1 << 2,
|
||||
ADDRESS_FAMILY_FALLBACK = ADDRESS_FAMILY_FALLBACK_IPV4 | ADDRESS_FAMILY_IPV6,
|
||||
_ADDRESS_FAMILY_MAX,
|
||||
_ADDRESS_FAMILY_INVALID = -1,
|
||||
} AddressFamily;
|
||||
@ -32,6 +34,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_address_family_with_kernel);
|
||||
const char *address_family_to_string(AddressFamily b) _const_;
|
||||
AddressFamily address_family_from_string(const char *s) _pure_;
|
||||
|
||||
const char *link_local_address_family_to_string(AddressFamily b) _const_;
|
||||
AddressFamily link_local_address_family_from_string(const char *s) _pure_;
|
||||
|
||||
const char *routing_policy_rule_address_family_to_string(AddressFamily b) _const_;
|
||||
|
||||
@ -1589,10 +1589,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, j ?: p, UINT64_MAX, SIZE_MAX,
|
||||
flags,
|
||||
NULL,
|
||||
&data, &size);
|
||||
r = read_full_file_full(AT_FDCWD, j ?: p, flags, NULL, &data, &size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read credential '%s': %m", j ?: p);
|
||||
|
||||
|
||||
@ -3621,11 +3621,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
_cleanup_(erase_and_freep) char *k = NULL;
|
||||
size_t n = 0;
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&k, &n);
|
||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_SECURE|READ_FULL_FILE_CONNECT_SOCKET, NULL, &k, &n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read key file '%s': %m", optarg);
|
||||
|
||||
|
||||
@ -2115,7 +2115,7 @@ int verity_settings_load(
|
||||
|
||||
if (verity->root_hash && !verity->root_hash_sig) {
|
||||
if (root_hash_sig_path) {
|
||||
r = read_full_file(root_hash_sig_path, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
@ -2131,7 +2131,7 @@ int verity_settings_load(
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
r = read_full_file_full(AT_FDCWD, p, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r >= 0)
|
||||
@ -2145,7 +2145,7 @@ int verity_settings_load(
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
r = read_full_file_full(AT_FDCWD, p, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r >= 0)
|
||||
|
||||
@ -3195,7 +3195,7 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags fla
|
||||
if (f)
|
||||
r = read_full_stream(f, &text, NULL);
|
||||
else if (path)
|
||||
r = read_full_file_full(dir_fd, path, UINT64_MAX, SIZE_MAX, 0, NULL, &text, NULL);
|
||||
r = read_full_file_full(dir_fd, path, 0, NULL, &text, NULL);
|
||||
else
|
||||
return -EINVAL;
|
||||
if (r < 0)
|
||||
|
||||
@ -40,8 +40,6 @@ enum {
|
||||
SD_DHCP_CLIENT_EVENT_EXPIRED = 3,
|
||||
SD_DHCP_CLIENT_EVENT_RENEW = 4,
|
||||
SD_DHCP_CLIENT_EVENT_SELECTING = 5,
|
||||
SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts.
|
||||
* The client may want to start acquiring link-local addresses. */
|
||||
};
|
||||
|
||||
enum {
|
||||
|
||||
@ -162,9 +162,6 @@ int sd_event_source_get_floating(sd_event_source *s);
|
||||
int sd_event_source_set_floating(sd_event_source *s, int b);
|
||||
int sd_event_source_get_exit_on_failure(sd_event_source *s);
|
||||
int sd_event_source_set_exit_on_failure(sd_event_source *s, int b);
|
||||
int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst);
|
||||
int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst);
|
||||
int sd_event_source_is_ratelimited(sd_event_source *s);
|
||||
|
||||
/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);
|
||||
|
||||
@ -911,8 +911,8 @@ static void test_read_full_file_socket(void) {
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, j, UINT64_MAX, SIZE_MAX, 0, NULL, &data, &size) == -ENXIO);
|
||||
assert_se(read_full_file_full(AT_FDCWD, j, UINT64_MAX, SIZE_MAX, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0);
|
||||
assert_se(read_full_file_full(AT_FDCWD, j, 0, NULL, &data, &size) == -ENXIO);
|
||||
assert_se(read_full_file_full(AT_FDCWD, j, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0);
|
||||
assert_se(size == strlen(TEST_STR));
|
||||
assert_se(streq(data, TEST_STR));
|
||||
|
||||
@ -920,50 +920,6 @@ static void test_read_full_file_socket(void) {
|
||||
#undef TEST_STR
|
||||
}
|
||||
|
||||
static void test_read_full_file_offset_size(void) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_(unlink_and_freep) char *fn = NULL;
|
||||
_cleanup_free_ char *rbuf = NULL;
|
||||
size_t rbuf_size;
|
||||
uint8_t buf[4711];
|
||||
|
||||
random_bytes(buf, sizeof(buf));
|
||||
|
||||
assert_se(tempfn_random_child(NULL, NULL, &fn) >= 0);
|
||||
assert_se(f = fopen(fn, "we"));
|
||||
assert_se(fwrite(buf, 1, sizeof(buf), f) == sizeof(buf));
|
||||
assert_se(fflush_and_check(f) >= 0);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, SIZE_MAX, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == sizeof(buf));
|
||||
assert_se(memcmp(buf, rbuf, rbuf_size) == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, 128, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == 128);
|
||||
assert_se(memcmp(buf, rbuf, rbuf_size) == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, 1234, SIZE_MAX, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == sizeof(buf) - 1234);
|
||||
assert_se(memcmp(buf + 1234, rbuf, rbuf_size) == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, 2345, 777, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == 777);
|
||||
assert_se(memcmp(buf + 2345, rbuf, rbuf_size) == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, 4700, 20, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == 11);
|
||||
assert_se(memcmp(buf + 4700, rbuf, rbuf_size) == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, 10000, 99, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
@ -990,7 +946,6 @@ int main(int argc, char *argv[]) {
|
||||
test_read_line4();
|
||||
test_read_nul_string();
|
||||
test_read_full_file_socket();
|
||||
test_read_full_file_offset_size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -100,11 +100,7 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", argv[6]);
|
||||
} else {
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, argv[6], UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&hash_sig, &hash_sig_size);
|
||||
r = read_full_file_full(AT_FDCWD, argv[6], READ_FULL_FILE_CONNECT_SOCKET, NULL, &hash_sig, &hash_sig_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read root hash signature: %m");
|
||||
}
|
||||
|
||||
@ -4,4 +4,5 @@ Name=veth99
|
||||
[Network]
|
||||
DHCP=yes
|
||||
IPv6AcceptRA=yes
|
||||
LinkLocalAddressing=yes
|
||||
VRF=vrf99
|
||||
|
||||
@ -3,5 +3,5 @@ Name=veth99
|
||||
|
||||
[Network]
|
||||
DHCP=ipv4
|
||||
LinkLocalAddressing=yes
|
||||
LinkLocalAddressing=fallback
|
||||
IPv6AcceptRA=no
|
||||
@ -3,7 +3,7 @@ Name=veth99
|
||||
|
||||
[Network]
|
||||
DHCP=ipv4
|
||||
LinkLocalAddressing=yes
|
||||
LinkLocalAddressing=fallback
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[DHCPv4]
|
||||
@ -3428,8 +3428,8 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
||||
'dhcp-client-use-dns-yes.network',
|
||||
'dhcp-client-use-domains.network',
|
||||
'dhcp-client-vrf.network',
|
||||
'dhcp-client-with-ipv4ll-with-dhcp-server.network',
|
||||
'dhcp-client-with-ipv4ll-without-dhcp-server.network',
|
||||
'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
|
||||
'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
|
||||
'dhcp-client-with-static-address.network',
|
||||
'dhcp-client.network',
|
||||
'dhcp-server-decline.network',
|
||||
@ -3925,6 +3925,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
||||
print('## ip address show vrf vrf99')
|
||||
output = check_output('ip address show vrf vrf99')
|
||||
print(output)
|
||||
self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
|
||||
self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
|
||||
self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
|
||||
self.assertRegex(output, 'inet6 .* scope link')
|
||||
@ -3932,6 +3933,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
||||
print('## ip address show dev veth99')
|
||||
output = check_output('ip address show dev veth99')
|
||||
print(output)
|
||||
self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
|
||||
self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
|
||||
self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
|
||||
self.assertRegex(output, 'inet6 .* scope link')
|
||||
@ -3940,6 +3942,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
||||
output = check_output('ip route show vrf vrf99')
|
||||
print(output)
|
||||
self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
|
||||
self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
|
||||
self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
|
||||
self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
|
||||
self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
|
||||
@ -3992,9 +3995,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
||||
print(output)
|
||||
self.assertRegex(output, 'onlink')
|
||||
|
||||
def test_dhcp_client_with_ipv4ll_with_dhcp_server(self):
|
||||
def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
|
||||
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
|
||||
'dhcp-client-with-ipv4ll-with-dhcp-server.network')
|
||||
'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
|
||||
start_networkd()
|
||||
self.wait_online(['veth-peer:carrier'])
|
||||
start_dnsmasq(lease_time='2m')
|
||||
@ -4029,9 +4032,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
||||
|
||||
search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
|
||||
|
||||
def test_dhcp_client_with_ipv4ll_without_dhcp_server(self):
|
||||
def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
|
||||
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
|
||||
'dhcp-client-with-ipv4ll-without-dhcp-server.network')
|
||||
'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
|
||||
start_networkd()
|
||||
self.wait_online(['veth99:degraded', 'veth-peer:routable'])
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user