mirror of
https://github.com/systemd/systemd
synced 2025-12-27 19:34:47 +01:00
Compare commits
37 Commits
e9eec8b5d2
...
0a67dd8310
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a67dd8310 | ||
|
|
f319b2b1b0 | ||
|
|
946f3d868c | ||
|
|
a303686fc1 | ||
|
|
d586f642fd | ||
|
|
68d8906517 | ||
|
|
b6d5481b3d | ||
|
|
f41315fceb | ||
|
|
cad143a8f2 | ||
|
|
f814c871e6 | ||
|
|
e6a7bee538 | ||
|
|
1e45e3fecc | ||
|
|
41c63f36c3 | ||
|
|
f80a5d6a86 | ||
|
|
8c437318b8 | ||
|
|
59d6f7b097 | ||
|
|
96e9a9a4e6 | ||
|
|
e060ed32e4 | ||
|
|
e2c2f868b2 | ||
|
|
4d1bb8f397 | ||
|
|
986311c2da | ||
|
|
c61f46fe31 | ||
|
|
ce82de671f | ||
|
|
e5de42e6f2 | ||
|
|
8b3c3a4973 | ||
|
|
ae9cf30b2f | ||
|
|
f362fe731b | ||
|
|
53ec5dd028 | ||
|
|
0d0799daf4 | ||
|
|
0b4b66cc53 | ||
|
|
d19b993983 | ||
|
|
8ccae2dd2d | ||
|
|
0107b769b1 | ||
|
|
fb536bc5da | ||
|
|
3ca1fab70a | ||
|
|
e4dc0845bc | ||
|
|
573b02f5c1 |
3
TODO
3
TODO
@ -76,9 +76,6 @@ Features:
|
|||||||
|
|
||||||
* make use of new glibc 2.32 APIs sigabbrev_np() and strerrorname_np().
|
* 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
|
* when main nspawn supervisor process gets suspended due to SIGSTOP/SIGTTOU or
|
||||||
so, freeze the payload too.
|
so, freeze the payload too.
|
||||||
|
|
||||||
|
|||||||
@ -53,25 +53,36 @@
|
|||||||
it is opened as a LUKS device; otherwise, it is assumed to be in
|
it is opened as a LUKS device; otherwise, it is assumed to be in
|
||||||
raw dm-crypt (plain mode) format.</para>
|
raw dm-crypt (plain mode) format.</para>
|
||||||
|
|
||||||
<para>The first field contains the name of the resulting encrypted volume; its block device is set up
|
<para>The four fields of <filename>/etc/crypttab</filename> are defined as follows:</para>
|
||||||
below <filename>/dev/mapper/</filename>.</para>
|
|
||||||
|
|
||||||
<para>The second field contains a path to the underlying block
|
<orderedlist>
|
||||||
device or file, or a specification of a block device via
|
|
||||||
<literal>UUID=</literal> followed by the UUID.</para>
|
|
||||||
|
|
||||||
<para>The third field specifies an absolute path to a file with the encryption key. Optionally,
|
<listitem><para>The first field contains the name of the resulting volume with decrypted data; its
|
||||||
the path may be followed by <literal>:</literal> and an fstab device specification (e.g. starting with
|
block device is set up below <filename>/dev/mapper/</filename>.</para></listitem>
|
||||||
<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>
|
|
||||||
|
|
||||||
<para>The fourth field, if present, is a comma-delimited list of
|
<listitem><para>The second field contains a path to the underlying block
|
||||||
options. The following options are recognized:</para>
|
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>
|
||||||
|
|
||||||
<variablelist class='fstab-options'>
|
<variablelist class='fstab-options'>
|
||||||
|
|
||||||
@ -499,6 +510,34 @@
|
|||||||
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||||
</refsect1>
|
</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>
|
<refsect1>
|
||||||
<title>Examples</title>
|
<title>Examples</title>
|
||||||
<example>
|
<example>
|
||||||
@ -529,7 +568,6 @@ external /dev/sda3 keyfile:LABEL=keydev keyfile-timeout=10s,cipher=xchac
|
|||||||
<para>A few notes on the above:</para>
|
<para>A few notes on the above:</para>
|
||||||
|
|
||||||
<itemizedlist>
|
<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>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>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,
|
<listitem><para>We use Yubikey key slot 9d, since that's apparently the keyslot to use for decryption purposes,
|
||||||
|
|||||||
@ -582,6 +582,10 @@ manpages = [
|
|||||||
'SD_EVENT_PRIORITY_NORMAL',
|
'SD_EVENT_PRIORITY_NORMAL',
|
||||||
'sd_event_source_get_priority'],
|
'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_set_userdata', '3', ['sd_event_source_get_userdata'], ''],
|
||||||
['sd_event_source_unref',
|
['sd_event_source_unref',
|
||||||
'3',
|
'3',
|
||||||
|
|||||||
@ -56,6 +56,7 @@
|
|||||||
<citerefentry><refentrytitle>sd_event_source_get_pending</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
<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_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>sd_event_source_set_prepare</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_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>sd_event_get_fd</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>,
|
<citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||||
@ -147,6 +148,7 @@
|
|||||||
<citerefentry><refentrytitle>sd_event_source_get_pending</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
<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_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>sd_event_source_set_prepare</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_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>sd_event_get_fd</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>,
|
<citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||||
|
|||||||
@ -147,7 +147,8 @@
|
|||||||
<citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
<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_inotify</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>sd_event_add_defer</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_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||||
|
<citerefentry><refentrytitle>sd_event_source_set_ratelimit</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|||||||
148
man/sd_event_source_set_ratelimit.xml
Normal file
148
man/sd_event_source_set_ratelimit.xml
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<?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>
|
<term><option>--key=</option></term>
|
||||||
|
|
||||||
<listitem><para>Specify the path to a file or <constant>AF_UNIX</constant> stream socket to read the
|
<listitem><para>Specify the path to a file or <constant>AF_UNIX</constant> stream socket to read the
|
||||||
server key corresponding to the certificate specified with <option>--cert=</option> from. The key
|
secret server key corresponding to the certificate specified with <option>--cert=</option> from. The
|
||||||
must be in PEM format.</para></listitem>
|
key must be in PEM format.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|||||||
@ -180,7 +180,7 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--key=</option></term>
|
<term><option>--key=</option></term>
|
||||||
|
|
||||||
<listitem><para> Takes a path to a SSL key file in PEM format. Defaults to
|
<listitem><para>Takes a path to a SSL secret key file in PEM format. Defaults to
|
||||||
<filename>&CERTIFICATE_ROOT;/private/journal-remote.pem</filename>. This option can be used with
|
<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
|
<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>
|
in the file system a connection is made to it and the key read from it.</para></listitem>
|
||||||
|
|||||||
@ -364,17 +364,15 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>LinkLocalAddressing=</varname></term>
|
<term><varname>LinkLocalAddressing=</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>Enables link-local address autoconfiguration. Accepts <literal>yes</literal>,
|
<para>Enables link-local address autoconfiguration. Accepts <option>yes</option>,
|
||||||
<literal>no</literal>, <literal>ipv4</literal>, <literal>ipv6</literal>,
|
<option>no</option>, <option>ipv4</option>, and <option>ipv6</option>. An IPv6 link-local address
|
||||||
<literal>fallback</literal>, or <literal>ipv4-fallback</literal>. If
|
is configured when <option>yes</option> or <option>ipv6</option>. An IPv4 link-local address is
|
||||||
<literal>fallback</literal> or <literal>ipv4-fallback</literal> is specified, then an IPv4
|
configured when <option>yes</option> or <option>ipv4</option> and when DHCPv4 autoconfiguration
|
||||||
link-local address is configured only when DHCPv4 fails. If <literal>fallback</literal>,
|
has been unsuccessful for some time. (IPv4 link-local address autoconfiguration will usually
|
||||||
an IPv6 link-local address is always configured, and if <literal>ipv4-fallback</literal>,
|
happen in parallel with repeated attempts to acquire a DHCPv4 lease).</para>
|
||||||
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
|
<para>Defaults to <option>no</option> when <varname>Bridge=yes</varname> is set, and
|
||||||
<literal>DHCP=ipv4</literal>. If <varname>Bridge=</varname> is set, defaults to
|
<option>ipv6</option> otherwise.</para>
|
||||||
<literal>no</literal>, and if not, defaults to <literal>ipv6</literal>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
@ -1664,9 +1662,10 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
|
|||||||
<term><varname>MaxAttempts=</varname></term>
|
<term><varname>MaxAttempts=</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>Specifies how many times the DHCPv4 client configuration should be attempted. Takes a
|
<para>Specifies how many times the DHCPv4 client configuration should be attempted. Takes a
|
||||||
number or <literal>infinity</literal>. Defaults to <literal>infinity</literal>.
|
number or <literal>infinity</literal>. Defaults to <literal>infinity</literal>. Note that the
|
||||||
Note that the time between retries is increased exponentially, so the network will not be
|
time between retries is increased exponentially, up to approximately one per minute, so the
|
||||||
overloaded even if this number is high.</para>
|
network will not be overloaded even if this number is high. The default is suitable in most
|
||||||
|
circumstances.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|||||||
@ -472,12 +472,13 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
|
|||||||
int read_full_stream_full(
|
int read_full_stream_full(
|
||||||
FILE *f,
|
FILE *f,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
uint64_t offset,
|
||||||
|
size_t size,
|
||||||
ReadFullFileFlags flags,
|
ReadFullFileFlags flags,
|
||||||
char **ret_contents,
|
char **ret_contents,
|
||||||
size_t *ret_size) {
|
size_t *ret_size) {
|
||||||
|
|
||||||
_cleanup_free_ char *buf = NULL;
|
_cleanup_free_ char *buf = NULL;
|
||||||
struct stat st;
|
|
||||||
size_t n, n_next, l;
|
size_t n, n_next, l;
|
||||||
int fd, r;
|
int fd, r;
|
||||||
|
|
||||||
@ -485,32 +486,45 @@ int read_full_stream_full(
|
|||||||
assert(ret_contents);
|
assert(ret_contents);
|
||||||
assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
|
assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
|
||||||
|
|
||||||
n_next = LINE_MAX; /* Start size */
|
if (offset != UINT64_MAX && offset > LONG_MAX)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
n_next = size != SIZE_MAX ? size : LINE_MAX; /* Start size */
|
||||||
|
|
||||||
fd = fileno(f);
|
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
|
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see
|
||||||
* optimize our buffering */
|
* fmemopen()), let's optimize our buffering */
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
if (fstat(fd, &st) < 0)
|
if (fstat(fd, &st) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (S_ISREG(st.st_mode)) {
|
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 */
|
/* Safety check */
|
||||||
if (st.st_size > READ_FULL_BYTES_MAX)
|
if (rsize > READ_FULL_BYTES_MAX)
|
||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
|
|
||||||
/* Start with the right file size. Note that we increase the size
|
/* Start with the right file size. Note that we increase the size to read
|
||||||
* to read here by one, so that the first read attempt already
|
* here by one, so that the first read attempt already makes us notice the
|
||||||
* makes us notice the EOF. */
|
* EOF. If the reported size of the file is zero, we avoid this logic
|
||||||
if (st.st_size > 0)
|
* however, since quite likely it might be a virtual file in procfs that all
|
||||||
n_next = st.st_size + 1;
|
* report a zero file size. */
|
||||||
|
if (st.st_size > 0)
|
||||||
|
n_next = rsize + 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
|
if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
|
||||||
(void) warn_file_is_world_accessible(filename, &st, NULL, 0);
|
(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;
|
n = l = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char *t;
|
char *t;
|
||||||
@ -547,6 +561,11 @@ int read_full_stream_full(
|
|||||||
if (feof(f))
|
if (feof(f))
|
||||||
break;
|
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 */
|
assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
|
||||||
|
|
||||||
/* Safety check */
|
/* Safety check */
|
||||||
@ -605,15 +624,18 @@ finalize:
|
|||||||
int read_full_file_full(
|
int read_full_file_full(
|
||||||
int dir_fd,
|
int dir_fd,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
uint64_t offset,
|
||||||
|
size_t size,
|
||||||
ReadFullFileFlags flags,
|
ReadFullFileFlags flags,
|
||||||
const char *bind_name,
|
const char *bind_name,
|
||||||
char **contents, size_t *size) {
|
char **ret_contents,
|
||||||
|
size_t *ret_size) {
|
||||||
|
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
assert(contents);
|
assert(ret_contents);
|
||||||
|
|
||||||
r = xfopenat(dir_fd, filename, "re", 0, &f);
|
r = xfopenat(dir_fd, filename, "re", 0, &f);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@ -628,6 +650,10 @@ int read_full_file_full(
|
|||||||
if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
|
if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
|
/* Seeking is not supported on AF_UNIX sockets */
|
||||||
|
if (offset != UINT64_MAX)
|
||||||
|
return -ESPIPE;
|
||||||
|
|
||||||
if (dir_fd == AT_FDCWD)
|
if (dir_fd == AT_FDCWD)
|
||||||
r = sockaddr_un_set_path(&sa.un, filename);
|
r = sockaddr_un_set_path(&sa.un, filename);
|
||||||
else {
|
else {
|
||||||
@ -681,7 +707,7 @@ int read_full_file_full(
|
|||||||
|
|
||||||
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
||||||
|
|
||||||
return read_full_stream_full(f, filename, flags, contents, size);
|
return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int executable_is_script(const char *path, char **interpreter) {
|
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 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_one_line_file(const char *filename, char **line);
|
||||||
int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, const char *bind_name, char **contents, size_t *size);
|
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 **contents, size_t *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, 0, NULL, contents, size);
|
return read_full_file_full(AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size);
|
||||||
}
|
}
|
||||||
int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_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, ReadFullFileFlags flags, char **contents, size_t *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 **contents, size_t *size) {
|
static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_size) {
|
||||||
return read_full_stream_full(f, NULL, 0, contents, size);
|
return read_full_stream_full(f, NULL, UINT64_MAX, SIZE_MAX, 0, ret_contents, ret_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
|
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
|
||||||
|
|||||||
@ -28,13 +28,12 @@ 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) \
|
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
|
||||||
scope type name##_from_string(const char *s) { \
|
scope type name##_from_string(const char *s) { \
|
||||||
int b; \
|
|
||||||
if (!s) \
|
if (!s) \
|
||||||
return -1; \
|
return -1; \
|
||||||
b = parse_boolean(s); \
|
int b = parse_boolean(s); \
|
||||||
if (b == 0) \
|
if (b == 0) \
|
||||||
return (type) 0; \
|
return (type) 0; \
|
||||||
else if (b > 0) \
|
if (b > 0) \
|
||||||
return yes; \
|
return yes; \
|
||||||
return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
|
return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2576,7 +2576,7 @@ static int acquire_credentials(
|
|||||||
|
|
||||||
|
|
||||||
if (source)
|
if (source)
|
||||||
r = read_full_file_full(AT_FDCWD, source, flags, bindname, &data, &size);
|
r = read_full_file_full(AT_FDCWD, source, UINT64_MAX, SIZE_MAX, flags, bindname, &data, &size);
|
||||||
else
|
else
|
||||||
r = -ENOENT;
|
r = -ENOENT;
|
||||||
if (r == -ENOENT &&
|
if (r == -ENOENT &&
|
||||||
|
|||||||
@ -1855,6 +1855,12 @@ static void mount_enumerate(Manager *m) {
|
|||||||
goto fail;
|
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");
|
(void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,29 +1,18 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "cryptsetup-keyfile.h"
|
#include "cryptsetup-keyfile.h"
|
||||||
#include "fd-util.h"
|
#include "fileio.h"
|
||||||
#include "format-util.h"
|
|
||||||
#include "memory-util.h"
|
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "stat-util.h"
|
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
|
||||||
#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
|
int find_key_file(
|
||||||
|
|
||||||
int load_key_file(
|
|
||||||
const char *key_file,
|
const char *key_file,
|
||||||
char **search_path,
|
char **search_path,
|
||||||
size_t key_file_size,
|
const char *bindname,
|
||||||
uint64_t key_file_offset,
|
|
||||||
void **ret_key,
|
void **ret_key,
|
||||||
size_t *ret_key_size) {
|
size_t *ret_key_size) {
|
||||||
|
|
||||||
_cleanup_(erase_and_freep) char *buffer = NULL;
|
char **i;
|
||||||
_cleanup_free_ char *discovered_path = NULL;
|
|
||||||
_cleanup_close_ int fd = -1;
|
|
||||||
ssize_t n;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(key_file);
|
assert(key_file);
|
||||||
@ -31,80 +20,38 @@ int load_key_file(
|
|||||||
assert(ret_key_size);
|
assert(ret_key_size);
|
||||||
|
|
||||||
if (strv_isempty(search_path) || path_is_absolute(key_file)) {
|
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;
|
|
||||||
|
|
||||||
STRV_FOREACH(i, search_path) {
|
r = read_full_file_full(
|
||||||
_cleanup_free_ char *joined;
|
AT_FDCWD, key_file, UINT64_MAX, SIZE_MAX,
|
||||||
|
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||||
joined = path_join(*i, key_file);
|
bindname,
|
||||||
if (!joined)
|
(char**) ret_key, ret_key_size);
|
||||||
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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Key file is not a regular file: %m");
|
return log_error_errno(r, "Failed to load key file '%s': %m", key_file);
|
||||||
|
|
||||||
if (st.st_size == 0)
|
return 1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = malloc(key_file_size);
|
STRV_FOREACH(i, search_path) {
|
||||||
if (!buffer)
|
_cleanup_free_ char *joined;
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
if (key_file_offset > 0)
|
joined = path_join(*i, key_file);
|
||||||
n = pread(fd, buffer, key_file_size, key_file_offset);
|
if (!joined)
|
||||||
else
|
return log_oom();
|
||||||
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.");
|
|
||||||
|
|
||||||
*ret_key = TAKE_PTR(buffer);
|
r = read_full_file_full(
|
||||||
*ret_key_size = (size_t) n;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
/* Search path supplied, but file not found, report by returning NULL, but not failing */
|
||||||
|
*ret_key = NULL;
|
||||||
|
*ret_key_size = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,10 +4,9 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
int load_key_file(
|
int find_key_file(
|
||||||
const char *key_file,
|
const char *key_file,
|
||||||
char **search_path,
|
char **search_path,
|
||||||
size_t key_file_size,
|
const char *bindname,
|
||||||
uint64_t key_file_offset,
|
|
||||||
void **ret_key,
|
void **ret_key,
|
||||||
size_t *ret_key_size);
|
size_t *ret_key_size);
|
||||||
|
|||||||
@ -10,13 +10,14 @@
|
|||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "ask-password-api.h"
|
#include "ask-password-api.h"
|
||||||
#include "cryptsetup-pkcs11.h"
|
#include "cryptsetup-pkcs11.h"
|
||||||
#include "cryptsetup-keyfile.h"
|
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
|
#include "fileio.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
#include "pkcs11-util.h"
|
#include "pkcs11-util.h"
|
||||||
|
#include "random-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
|
||||||
@ -95,6 +96,7 @@ static int pkcs11_callback(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int decrypt_pkcs11_key(
|
int decrypt_pkcs11_key(
|
||||||
|
const char *volume_name,
|
||||||
const char *friendly_name,
|
const char *friendly_name,
|
||||||
const char *pkcs11_uri,
|
const char *pkcs11_uri,
|
||||||
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
|
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
|
||||||
@ -126,7 +128,19 @@ int decrypt_pkcs11_key(
|
|||||||
|
|
||||||
data.free_encrypted_key = false;
|
data.free_encrypted_key = false;
|
||||||
} else {
|
} else {
|
||||||
r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
|
_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);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#if HAVE_P11KIT
|
#if HAVE_P11KIT
|
||||||
|
|
||||||
int decrypt_pkcs11_key(
|
int decrypt_pkcs11_key(
|
||||||
|
const char *volume_name,
|
||||||
const char *friendly_name,
|
const char *friendly_name,
|
||||||
const char *pkcs11_uri,
|
const char *pkcs11_uri,
|
||||||
const char *key_file,
|
const char *key_file,
|
||||||
@ -23,6 +24,7 @@ int decrypt_pkcs11_key(
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int decrypt_pkcs11_key(
|
static inline int decrypt_pkcs11_key(
|
||||||
|
const char *volume_name,
|
||||||
const char *friendly_name,
|
const char *friendly_name,
|
||||||
const char *pkcs11_uri,
|
const char *pkcs11_uri,
|
||||||
const char *key_file,
|
const char *key_file,
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "pkcs11-util.h"
|
#include "pkcs11-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
|
#include "random-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
|
||||||
@ -550,6 +551,15 @@ static int attach_tcrypt(
|
|||||||
return 0;
|
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(
|
static int attach_luks_or_plain_or_bitlk(
|
||||||
struct crypt_device *cd,
|
struct crypt_device *cd,
|
||||||
const char *name,
|
const char *name,
|
||||||
@ -636,6 +646,7 @@ static int attach_luks_or_plain_or_bitlk(
|
|||||||
bool processed = false;
|
bool processed = false;
|
||||||
|
|
||||||
r = decrypt_pkcs11_key(
|
r = decrypt_pkcs11_key(
|
||||||
|
name,
|
||||||
friendly,
|
friendly,
|
||||||
arg_pkcs11_uri,
|
arg_pkcs11_uri,
|
||||||
key_file, arg_keyfile_size, arg_keyfile_offset,
|
key_file, arg_keyfile_size, arg_keyfile_offset,
|
||||||
@ -735,13 +746,30 @@ static int attach_luks_or_plain_or_bitlk(
|
|||||||
return log_error_errno(r, "Failed to activate: %m");
|
return log_error_errno(r, "Failed to activate: %m");
|
||||||
|
|
||||||
} else if (key_file) {
|
} else if (key_file) {
|
||||||
r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
|
_cleanup_(erase_and_freep) char *kfdata = NULL;
|
||||||
if (r == -EPERM) {
|
_cleanup_free_ char *bindname = NULL;
|
||||||
log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
|
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 */
|
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);
|
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, kfdata, kfsize, 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 */
|
return -EAGAIN; /* Log actual error, but return EAGAIN */
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -880,16 +908,22 @@ static int run(int argc, char *argv[]) {
|
|||||||
(void) mlockall(MCL_FUTURE);
|
(void) mlockall(MCL_FUTURE);
|
||||||
|
|
||||||
if (!key_file) {
|
if (!key_file) {
|
||||||
|
_cleanup_free_ char *bindname = NULL;
|
||||||
const char *fn;
|
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
|
/* If a key file is not explicitly specified, search for a key in a well defined
|
||||||
* search path, and load it. */
|
* search path, and load it. */
|
||||||
|
|
||||||
fn = strjoina(argv[2], ".key");
|
fn = strjoina(argv[2], ".key");
|
||||||
r = load_key_file(fn,
|
r = find_key_file(
|
||||||
STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
|
fn,
|
||||||
0, 0, /* Note we leave arg_keyfile_offset/arg_keyfile_size as something that only applies to arg_keyfile! */
|
STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
|
||||||
&key_data, &key_data_size);
|
bindname,
|
||||||
|
&key_data, &key_data_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "logs-show.h"
|
#include "logs-show.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
|
#include "memory-util.h"
|
||||||
#include "microhttpd-util.h"
|
#include "microhttpd-util.h"
|
||||||
#include "os-util.h"
|
#include "os-util.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
@ -37,7 +38,7 @@ static char *arg_cert_pem = NULL;
|
|||||||
static char *arg_trust_pem = NULL;
|
static char *arg_trust_pem = NULL;
|
||||||
static const char *arg_directory = NULL;
|
static const char *arg_directory = NULL;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_key_pem, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_key_pem, erase_and_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_cert_pem, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_cert_pem, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_trust_pem, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_trust_pem, freep);
|
||||||
|
|
||||||
@ -896,7 +897,11 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
if (arg_key_pem)
|
if (arg_key_pem)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Key file specified twice");
|
"Key file specified twice");
|
||||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_key_pem, NULL);
|
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);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read key file: %m");
|
return log_error_errno(r, "Failed to read key file: %m");
|
||||||
assert(arg_key_pem);
|
assert(arg_key_pem);
|
||||||
@ -906,7 +911,11 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
if (arg_cert_pem)
|
if (arg_cert_pem)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Certificate file specified twice");
|
"Certificate file specified twice");
|
||||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_cert_pem, NULL);
|
r = read_full_file_full(
|
||||||
|
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||||
|
READ_FULL_FILE_CONNECT_SOCKET,
|
||||||
|
NULL,
|
||||||
|
&arg_cert_pem, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read certificate file: %m");
|
return log_error_errno(r, "Failed to read certificate file: %m");
|
||||||
assert(arg_cert_pem);
|
assert(arg_cert_pem);
|
||||||
@ -917,14 +926,18 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
if (arg_trust_pem)
|
if (arg_trust_pem)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"CA certificate file specified twice");
|
"CA certificate file specified twice");
|
||||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_trust_pem, NULL);
|
r = read_full_file_full(
|
||||||
|
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||||
|
READ_FULL_FILE_CONNECT_SOCKET,
|
||||||
|
NULL,
|
||||||
|
&arg_trust_pem, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read CA certificate file: %m");
|
return log_error_errno(r, "Failed to read CA certificate file: %m");
|
||||||
assert(arg_trust_pem);
|
assert(arg_trust_pem);
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Option --trust is not available.");
|
"Option --trust= is not available.");
|
||||||
#endif
|
#endif
|
||||||
case 'D':
|
case 'D':
|
||||||
arg_directory = optarg;
|
arg_directory = optarg;
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#include "journal-remote-write.h"
|
#include "journal-remote-write.h"
|
||||||
#include "journal-remote.h"
|
#include "journal-remote.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
|
#include "memory-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "rlimit-util.h"
|
#include "rlimit-util.h"
|
||||||
@ -1077,12 +1078,20 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
static int load_certificates(char **key, char **cert, char **trust) {
|
static int load_certificates(char **key, char **cert, char **trust) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = read_full_file_full(AT_FDCWD, arg_key ?: PRIV_KEY_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, key, NULL);
|
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);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read key from file '%s': %m",
|
return log_error_errno(r, "Failed to read key from file '%s': %m",
|
||||||
arg_key ?: PRIV_KEY_FILE);
|
arg_key ?: PRIV_KEY_FILE);
|
||||||
|
|
||||||
r = read_full_file_full(AT_FDCWD, arg_cert ?: CERT_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, cert, NULL);
|
r = read_full_file_full(
|
||||||
|
AT_FDCWD, arg_cert ?: CERT_FILE, UINT64_MAX, SIZE_MAX,
|
||||||
|
READ_FULL_FILE_CONNECT_SOCKET,
|
||||||
|
NULL,
|
||||||
|
cert, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read certificate from file '%s': %m",
|
return log_error_errno(r, "Failed to read certificate from file '%s': %m",
|
||||||
arg_cert ?: CERT_FILE);
|
arg_cert ?: CERT_FILE);
|
||||||
@ -1090,7 +1099,11 @@ static int load_certificates(char **key, char **cert, char **trust) {
|
|||||||
if (arg_trust_all)
|
if (arg_trust_all)
|
||||||
log_info("Certificate checking disabled.");
|
log_info("Certificate checking disabled.");
|
||||||
else {
|
else {
|
||||||
r = read_full_file_full(AT_FDCWD, arg_trust ?: TRUST_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, trust, NULL);
|
r = read_full_file_full(
|
||||||
|
AT_FDCWD, arg_trust ?: TRUST_FILE, UINT64_MAX, SIZE_MAX,
|
||||||
|
READ_FULL_FILE_CONNECT_SOCKET,
|
||||||
|
NULL,
|
||||||
|
trust, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
|
return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
|
||||||
arg_trust ?: TRUST_FILE);
|
arg_trust ?: TRUST_FILE);
|
||||||
@ -1106,7 +1119,8 @@ static int load_certificates(char **key, char **cert, char **trust) {
|
|||||||
static int run(int argc, char **argv) {
|
static int run(int argc, char **argv) {
|
||||||
_cleanup_(journal_remote_server_destroy) RemoteServer s = {};
|
_cleanup_(journal_remote_server_destroy) RemoteServer s = {};
|
||||||
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
|
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
|
||||||
_cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
|
_cleanup_(erase_and_freep) char *key = NULL;
|
||||||
|
_cleanup_free_ char *cert = NULL, *trust = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
log_show_color(true);
|
log_show_color(true);
|
||||||
|
|||||||
@ -38,6 +38,9 @@
|
|||||||
#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
|
#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
|
||||||
#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
|
#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 {
|
typedef struct sd_dhcp_client_id {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
union {
|
union {
|
||||||
@ -1187,7 +1190,7 @@ static int client_timeout_resend(
|
|||||||
|
|
||||||
sd_dhcp_client *client = userdata;
|
sd_dhcp_client *client = userdata;
|
||||||
DHCP_CLIENT_DONT_DESTROY(client);
|
DHCP_CLIENT_DONT_DESTROY(client);
|
||||||
usec_t next_timeout = 0;
|
usec_t next_timeout;
|
||||||
uint64_t time_now;
|
uint64_t time_now;
|
||||||
uint32_t time_left;
|
uint32_t time_left;
|
||||||
int r;
|
int r;
|
||||||
@ -1203,17 +1206,14 @@ static int client_timeout_resend(
|
|||||||
switch (client->state) {
|
switch (client->state) {
|
||||||
|
|
||||||
case DHCP_STATE_RENEWING:
|
case DHCP_STATE_RENEWING:
|
||||||
|
|
||||||
time_left = (client->lease->t2 - client->lease->t1) / 2;
|
time_left = (client->lease->t2 - client->lease->t1) / 2;
|
||||||
if (time_left < 60)
|
if (time_left < 60)
|
||||||
time_left = 60;
|
time_left = 60;
|
||||||
|
|
||||||
next_timeout = time_now + time_left * USEC_PER_SEC;
|
next_timeout = time_now + time_left * USEC_PER_SEC;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DHCP_STATE_REBINDING:
|
case DHCP_STATE_REBINDING:
|
||||||
|
|
||||||
time_left = (client->lease->lifetime - client->lease->t2) / 2;
|
time_left = (client->lease->lifetime - client->lease->t2) / 2;
|
||||||
if (time_left < 60)
|
if (time_left < 60)
|
||||||
time_left = 60;
|
time_left = 60;
|
||||||
@ -1230,24 +1230,20 @@ static int client_timeout_resend(
|
|||||||
r = client_start(client);
|
r = client_start(client);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
else {
|
|
||||||
log_dhcp_client(client, "REBOOTED");
|
log_dhcp_client(client, "REBOOTED");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
case DHCP_STATE_INIT:
|
case DHCP_STATE_INIT:
|
||||||
case DHCP_STATE_INIT_REBOOT:
|
case DHCP_STATE_INIT_REBOOT:
|
||||||
case DHCP_STATE_SELECTING:
|
case DHCP_STATE_SELECTING:
|
||||||
case DHCP_STATE_REQUESTING:
|
case DHCP_STATE_REQUESTING:
|
||||||
case DHCP_STATE_BOUND:
|
case DHCP_STATE_BOUND:
|
||||||
|
if (client->attempt >= client->max_attempts)
|
||||||
if (client->attempt < client->max_attempts)
|
|
||||||
client->attempt++;
|
|
||||||
else
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
client->attempt++;
|
||||||
next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
|
next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DHCP_STATE_STOPPED:
|
case DHCP_STATE_STOPPED:
|
||||||
@ -1295,12 +1291,10 @@ static int client_timeout_resend(
|
|||||||
client->state = DHCP_STATE_REBOOTING;
|
client->state = DHCP_STATE_REBOOTING;
|
||||||
|
|
||||||
client->request_sent = time_now;
|
client->request_sent = time_now;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DHCP_STATE_REBOOTING:
|
case DHCP_STATE_REBOOTING:
|
||||||
case DHCP_STATE_BOUND:
|
case DHCP_STATE_BOUND:
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DHCP_STATE_STOPPED:
|
case DHCP_STATE_STOPPED:
|
||||||
@ -1308,6 +1302,9 @@ static int client_timeout_resend(
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client->attempt >= TRANSIENT_FAILURE_ATTEMPTS)
|
||||||
|
client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|||||||
@ -736,3 +736,10 @@ global:
|
|||||||
sd_device_has_current_tag;
|
sd_device_has_current_tag;
|
||||||
sd_device_set_sysattr_valuef;
|
sd_device_set_sysattr_valuef;
|
||||||
} LIBSYSTEMD_246;
|
} LIBSYSTEMD_246;
|
||||||
|
|
||||||
|
LIBSYSTEMD_248 {
|
||||||
|
global:
|
||||||
|
sd_event_source_set_ratelimit;
|
||||||
|
sd_event_source_get_ratelimit;
|
||||||
|
sd_event_source_is_ratelimited;
|
||||||
|
} LIBSYSTEMD_246;
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "prioq.h"
|
#include "prioq.h"
|
||||||
|
#include "ratelimit.h"
|
||||||
|
|
||||||
typedef enum EventSourceType {
|
typedef enum EventSourceType {
|
||||||
SOURCE_IO,
|
SOURCE_IO,
|
||||||
@ -61,6 +62,7 @@ struct sd_event_source {
|
|||||||
bool dispatching:1;
|
bool dispatching:1;
|
||||||
bool floating:1;
|
bool floating:1;
|
||||||
bool exit_on_failure:1;
|
bool exit_on_failure:1;
|
||||||
|
bool ratelimited:1;
|
||||||
|
|
||||||
int64_t priority;
|
int64_t priority;
|
||||||
unsigned pending_index;
|
unsigned pending_index;
|
||||||
@ -72,6 +74,13 @@ struct sd_event_source {
|
|||||||
|
|
||||||
LIST_FIELDS(sd_event_source, sources);
|
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 {
|
union {
|
||||||
struct {
|
struct {
|
||||||
sd_event_io_handler_t callback;
|
sd_event_io_handler_t callback;
|
||||||
@ -84,8 +93,6 @@ struct sd_event_source {
|
|||||||
struct {
|
struct {
|
||||||
sd_event_time_handler_t callback;
|
sd_event_time_handler_t callback;
|
||||||
usec_t next, accuracy;
|
usec_t next, accuracy;
|
||||||
unsigned earliest_index;
|
|
||||||
unsigned latest_index;
|
|
||||||
} time;
|
} time;
|
||||||
struct {
|
struct {
|
||||||
sd_event_signal_handler_t callback;
|
sd_event_signal_handler_t callback;
|
||||||
|
|||||||
@ -37,6 +37,16 @@ static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) {
|
|||||||
s->child.options == WEXITED;
|
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] = {
|
static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
|
||||||
[SOURCE_IO] = "io",
|
[SOURCE_IO] = "io",
|
||||||
[SOURCE_TIME_REALTIME] = "realtime",
|
[SOURCE_TIME_REALTIME] = "realtime",
|
||||||
@ -55,7 +65,25 @@ 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_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_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)
|
||||||
|
|
||||||
struct sd_event {
|
struct sd_event {
|
||||||
unsigned n_ref;
|
unsigned n_ref;
|
||||||
@ -81,7 +109,7 @@ struct sd_event {
|
|||||||
Hashmap *signal_data; /* indexed by priority */
|
Hashmap *signal_data; /* indexed by priority */
|
||||||
|
|
||||||
Hashmap *child_sources;
|
Hashmap *child_sources;
|
||||||
unsigned n_enabled_child_sources;
|
unsigned n_online_child_sources;
|
||||||
|
|
||||||
Set *post_sources;
|
Set *post_sources;
|
||||||
|
|
||||||
@ -120,7 +148,7 @@ struct sd_event {
|
|||||||
|
|
||||||
LIST_HEAD(sd_event_source, sources);
|
LIST_HEAD(sd_event_source, sources);
|
||||||
|
|
||||||
usec_t last_run, last_log;
|
usec_t last_run_usec, last_log_usec;
|
||||||
unsigned delays[sizeof(usec_t) * 8];
|
unsigned delays[sizeof(usec_t) * 8];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,6 +174,11 @@ static int pending_prioq_compare(const void *a, const void *b) {
|
|||||||
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/* Non rate-limited ones first. */
|
||||||
|
r = CMP(!!x->ratelimited, !!y->ratelimited);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
/* Lower priority values first */
|
/* Lower priority values first */
|
||||||
r = CMP(x->priority, y->priority);
|
r = CMP(x->priority, y->priority);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
@ -168,6 +201,11 @@ static int prepare_prioq_compare(const void *a, const void *b) {
|
|||||||
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
|
||||||
return 1;
|
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
|
/* Move most recently prepared ones last, so that we can stop
|
||||||
* preparing as soon as we hit one that has already been
|
* preparing as soon as we hit one that has already been
|
||||||
* prepared in the current iteration */
|
* prepared in the current iteration */
|
||||||
@ -179,12 +217,30 @@ static int prepare_prioq_compare(const void *a, const void *b) {
|
|||||||
return CMP(x->priority, y->priority);
|
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) {
|
static int earliest_time_prioq_compare(const void *a, const void *b) {
|
||||||
const sd_event_source *x = a, *y = b;
|
const sd_event_source *x = a, *y = b;
|
||||||
|
|
||||||
assert(EVENT_SOURCE_IS_TIME(x->type));
|
|
||||||
assert(x->type == y->type);
|
|
||||||
|
|
||||||
/* Enabled ones first */
|
/* Enabled ones first */
|
||||||
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
||||||
return -1;
|
return -1;
|
||||||
@ -198,19 +254,30 @@ static int earliest_time_prioq_compare(const void *a, const void *b) {
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Order by time */
|
/* Order by time */
|
||||||
return CMP(x->time.next, y->time.next);
|
return CMP(time_event_source_next(x), time_event_source_next(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
static usec_t time_event_source_latest(const sd_event_source *s) {
|
static usec_t time_event_source_latest(const sd_event_source *s) {
|
||||||
return usec_add(s->time.next, s->time.accuracy);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int latest_time_prioq_compare(const void *a, const void *b) {
|
static int latest_time_prioq_compare(const void *a, const void *b) {
|
||||||
const sd_event_source *x = a, *y = b;
|
const sd_event_source *x = a, *y = b;
|
||||||
|
|
||||||
assert(EVENT_SOURCE_IS_TIME(x->type));
|
|
||||||
assert(x->type == y->type);
|
|
||||||
|
|
||||||
/* Enabled ones first */
|
/* Enabled ones first */
|
||||||
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
|
||||||
return -1;
|
return -1;
|
||||||
@ -380,7 +447,7 @@ static void source_io_unregister(sd_event_source *s) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0)
|
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: %m",
|
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m",
|
||||||
strna(s->description), event_source_type_to_string(s->type));
|
strna(s->description), event_source_type_to_string(s->type));
|
||||||
|
|
||||||
s->io.registered = false;
|
s->io.registered = false;
|
||||||
@ -422,7 +489,7 @@ static void source_child_pidfd_unregister(sd_event_source *s) {
|
|||||||
|
|
||||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||||
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0)
|
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: %m",
|
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m",
|
||||||
strna(s->description), event_source_type_to_string(s->type));
|
strna(s->description), event_source_type_to_string(s->type));
|
||||||
|
|
||||||
s->child.registered = false;
|
s->child.registered = false;
|
||||||
@ -661,12 +728,12 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig)
|
|||||||
* and possibly drop the signalfd for it. */
|
* and possibly drop the signalfd for it. */
|
||||||
|
|
||||||
if (sig == SIGCHLD &&
|
if (sig == SIGCHLD &&
|
||||||
e->n_enabled_child_sources > 0)
|
e->n_online_child_sources > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (e->signal_sources &&
|
if (e->signal_sources &&
|
||||||
e->signal_sources[sig] &&
|
e->signal_sources[sig] &&
|
||||||
e->signal_sources[sig]->enabled != SD_EVENT_OFF)
|
event_source_is_online(e->signal_sources[sig]))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -713,13 +780,32 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) {
|
|||||||
struct clock_data *d;
|
struct clock_data *d;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
assert(EVENT_SOURCE_IS_TIME(s->type));
|
|
||||||
|
|
||||||
/* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy,
|
/* 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. */
|
* pending, enable state. Makes sure the two prioq's are ordered properly again. */
|
||||||
assert_se(d = event_get_clock_data(s->event, s->type));
|
|
||||||
prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
|
if (s->ratelimited)
|
||||||
prioq_reshuffle(d->latest, s, &s->time.latest_index);
|
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;
|
||||||
d->needs_rearm = true;
|
d->needs_rearm = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,17 +831,18 @@ static void source_disconnect(sd_event_source *s) {
|
|||||||
case SOURCE_TIME_BOOTTIME:
|
case SOURCE_TIME_BOOTTIME:
|
||||||
case SOURCE_TIME_MONOTONIC:
|
case SOURCE_TIME_MONOTONIC:
|
||||||
case SOURCE_TIME_REALTIME_ALARM:
|
case SOURCE_TIME_REALTIME_ALARM:
|
||||||
case SOURCE_TIME_BOOTTIME_ALARM: {
|
case SOURCE_TIME_BOOTTIME_ALARM:
|
||||||
struct clock_data *d;
|
/* 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 */
|
||||||
|
|
||||||
d = event_get_clock_data(s->event, s->type);
|
if (!s->ratelimited) {
|
||||||
assert(d);
|
struct clock_data *d;
|
||||||
|
assert_se(d = event_get_clock_data(s->event, s->type));
|
||||||
|
event_source_time_prioq_remove(s, d);
|
||||||
|
}
|
||||||
|
|
||||||
prioq_remove(d->earliest, s, &s->time.earliest_index);
|
|
||||||
prioq_remove(d->latest, s, &s->time.latest_index);
|
|
||||||
d->needs_rearm = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case SOURCE_SIGNAL:
|
case SOURCE_SIGNAL:
|
||||||
if (s->signal.sig > 0) {
|
if (s->signal.sig > 0) {
|
||||||
@ -770,9 +857,9 @@ static void source_disconnect(sd_event_source *s) {
|
|||||||
|
|
||||||
case SOURCE_CHILD:
|
case SOURCE_CHILD:
|
||||||
if (s->child.pid > 0) {
|
if (s->child.pid > 0) {
|
||||||
if (s->enabled != SD_EVENT_OFF) {
|
if (event_source_is_online(s)) {
|
||||||
assert(s->event->n_enabled_child_sources > 0);
|
assert(s->event->n_online_child_sources > 0);
|
||||||
s->event->n_enabled_child_sources--;
|
s->event->n_online_child_sources--;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid));
|
(void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid));
|
||||||
@ -842,6 +929,9 @@ static void source_disconnect(sd_event_source *s) {
|
|||||||
if (s->prepare)
|
if (s->prepare)
|
||||||
prioq_remove(s->event->prepare, s, &s->prepare_index);
|
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);
|
event = TAKE_PTR(s->event);
|
||||||
LIST_REMOVE(sources, event->sources, s);
|
LIST_REMOVE(sources, event->sources, s);
|
||||||
event->n_sources--;
|
event->n_sources--;
|
||||||
@ -1088,6 +1178,52 @@ 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));
|
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(
|
_public_ int sd_event_add_time(
|
||||||
sd_event *e,
|
sd_event *e,
|
||||||
sd_event_source **ret,
|
sd_event_source **ret,
|
||||||
@ -1118,23 +1254,12 @@ _public_ int sd_event_add_time(
|
|||||||
if (!callback)
|
if (!callback)
|
||||||
callback = time_exit_callback;
|
callback = time_exit_callback;
|
||||||
|
|
||||||
d = event_get_clock_data(e, type);
|
assert_se(d = event_get_clock_data(e, type));
|
||||||
assert(d);
|
|
||||||
|
|
||||||
r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare);
|
r = setup_clock_data(e, d, clock);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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);
|
s = source_new(e, !ret, type);
|
||||||
if (!s)
|
if (!s)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -1142,17 +1267,11 @@ _public_ int sd_event_add_time(
|
|||||||
s->time.next = usec;
|
s->time.next = usec;
|
||||||
s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy;
|
s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy;
|
||||||
s->time.callback = callback;
|
s->time.callback = callback;
|
||||||
s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL;
|
s->earliest_index = s->latest_index = PRIOQ_IDX_NULL;
|
||||||
s->userdata = userdata;
|
s->userdata = userdata;
|
||||||
s->enabled = SD_EVENT_ONESHOT;
|
s->enabled = SD_EVENT_ONESHOT;
|
||||||
|
|
||||||
d->needs_rearm = true;
|
r = event_source_time_prioq_put(s, d);
|
||||||
|
|
||||||
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1285,7 +1404,7 @@ _public_ int sd_event_add_child(
|
|||||||
if (!callback)
|
if (!callback)
|
||||||
callback = child_exit_callback;
|
callback = child_exit_callback;
|
||||||
|
|
||||||
if (e->n_enabled_child_sources == 0) {
|
if (e->n_online_child_sources == 0) {
|
||||||
/* Caller must block SIGCHLD before using us to watch children, even if pidfd is available,
|
/* 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
|
* 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
|
* ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to
|
||||||
@ -1350,7 +1469,7 @@ _public_ int sd_event_add_child(
|
|||||||
e->need_process_child = true;
|
e->need_process_child = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
e->n_enabled_child_sources++;
|
e->n_online_child_sources++;
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
*ret = s;
|
*ret = s;
|
||||||
@ -1382,7 +1501,7 @@ _public_ int sd_event_add_child_pidfd(
|
|||||||
if (!callback)
|
if (!callback)
|
||||||
callback = child_exit_callback;
|
callback = child_exit_callback;
|
||||||
|
|
||||||
if (e->n_enabled_child_sources == 0) {
|
if (e->n_online_child_sources == 0) {
|
||||||
r = signal_is_blocked(SIGCHLD);
|
r = signal_is_blocked(SIGCHLD);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1432,7 +1551,7 @@ _public_ int sd_event_add_child_pidfd(
|
|||||||
e->need_process_child = true;
|
e->need_process_child = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
e->n_enabled_child_sources++;
|
e->n_online_child_sources++;
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
*ret = s;
|
*ret = s;
|
||||||
@ -2018,7 +2137,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
|
|||||||
if (s->io.fd == fd)
|
if (s->io.fd == fd)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (s->enabled == SD_EVENT_OFF) {
|
if (event_source_is_offline(s)) {
|
||||||
s->io.fd = fd;
|
s->io.fd = fd;
|
||||||
s->io.registered = false;
|
s->io.registered = false;
|
||||||
} else {
|
} else {
|
||||||
@ -2085,7 +2204,7 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events)
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (s->enabled != SD_EVENT_OFF) {
|
if (event_source_is_online(s)) {
|
||||||
r = source_io_register(s, s->enabled, events);
|
r = source_io_register(s, s->enabled, events);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -2188,7 +2307,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority)
|
|||||||
|
|
||||||
event_gc_inode_data(s->event, old_inode_data);
|
event_gc_inode_data(s->event, old_inode_data);
|
||||||
|
|
||||||
} else if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) {
|
} else if (s->type == SOURCE_SIGNAL && event_source_is_online(s)) {
|
||||||
struct signal_data *old, *d;
|
struct signal_data *old, *d;
|
||||||
|
|
||||||
/* Move us from the signalfd belonging to the old
|
/* Move us from the signalfd belonging to the old
|
||||||
@ -2225,29 +2344,39 @@ fail:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
|
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) {
|
||||||
assert_return(s, -EINVAL);
|
assert_return(s, -EINVAL);
|
||||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||||
|
|
||||||
if (m)
|
if (ret)
|
||||||
*m = s->enabled;
|
*ret = s->enabled;
|
||||||
|
|
||||||
return s->enabled != SD_EVENT_OFF;
|
return s->enabled != SD_EVENT_OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int event_source_disable(sd_event_source *s) {
|
static int event_source_offline(
|
||||||
|
sd_event_source *s,
|
||||||
|
int enabled,
|
||||||
|
bool ratelimited) {
|
||||||
|
|
||||||
|
bool was_offline;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
assert(s->enabled != SD_EVENT_OFF);
|
assert(enabled == SD_EVENT_OFF || ratelimited);
|
||||||
|
|
||||||
/* Unset the pending flag when this event source is disabled */
|
/* Unset the pending flag when this event source is disabled */
|
||||||
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
if (s->enabled != SD_EVENT_OFF &&
|
||||||
|
enabled == SD_EVENT_OFF &&
|
||||||
|
!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||||
r = source_set_pending(s, false);
|
r = source_set_pending(s, false);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->enabled = SD_EVENT_OFF;
|
was_offline = event_source_is_offline(s);
|
||||||
|
s->enabled = enabled;
|
||||||
|
s->ratelimited = ratelimited;
|
||||||
|
|
||||||
switch (s->type) {
|
switch (s->type) {
|
||||||
|
|
||||||
@ -2268,8 +2397,10 @@ static int event_source_disable(sd_event_source *s) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SOURCE_CHILD:
|
case SOURCE_CHILD:
|
||||||
assert(s->event->n_enabled_child_sources > 0);
|
if (!was_offline) {
|
||||||
s->event->n_enabled_child_sources--;
|
assert(s->event->n_online_child_sources > 0);
|
||||||
|
s->event->n_online_child_sources--;
|
||||||
|
}
|
||||||
|
|
||||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||||
source_child_pidfd_unregister(s);
|
source_child_pidfd_unregister(s);
|
||||||
@ -2290,26 +2421,42 @@ static int event_source_disable(sd_event_source *s) {
|
|||||||
assert_not_reached("Wut? I shouldn't exist.");
|
assert_not_reached("Wut? I shouldn't exist.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int event_source_enable(sd_event_source *s, int enable) {
|
static int event_source_online(
|
||||||
|
sd_event_source *s,
|
||||||
|
int enabled,
|
||||||
|
bool ratelimited) {
|
||||||
|
|
||||||
|
bool was_online;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
assert(IN_SET(enable, SD_EVENT_ON, SD_EVENT_ONESHOT));
|
assert(enabled != SD_EVENT_OFF || !ratelimited);
|
||||||
assert(s->enabled == SD_EVENT_OFF);
|
|
||||||
|
|
||||||
/* Unset the pending flag when this event source is enabled */
|
/* Unset the pending flag when this event source is enabled */
|
||||||
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
if (s->enabled == SD_EVENT_OFF &&
|
||||||
|
enabled != SD_EVENT_OFF &&
|
||||||
|
!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||||
r = source_set_pending(s, false);
|
r = source_set_pending(s, false);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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) {
|
switch (s->type) {
|
||||||
case SOURCE_IO:
|
case SOURCE_IO:
|
||||||
r = source_io_register(s, enable, s->io.events);
|
r = source_io_register(s, enabled, s->io.events);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
break;
|
break;
|
||||||
@ -2327,7 +2474,7 @@ static int event_source_enable(sd_event_source *s, int enable) {
|
|||||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||||
/* yes, we have pidfd */
|
/* yes, we have pidfd */
|
||||||
|
|
||||||
r = source_child_pidfd_register(s, enable);
|
r = source_child_pidfd_register(s, enabled);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
@ -2340,8 +2487,8 @@ static int event_source_enable(sd_event_source *s, int enable) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s->event->n_enabled_child_sources++;
|
if (!was_online)
|
||||||
|
s->event->n_online_child_sources++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOURCE_TIME_REALTIME:
|
case SOURCE_TIME_REALTIME:
|
||||||
@ -2359,7 +2506,8 @@ static int event_source_enable(sd_event_source *s, int enable) {
|
|||||||
assert_not_reached("Wut? I shouldn't exist.");
|
assert_not_reached("Wut? I shouldn't exist.");
|
||||||
}
|
}
|
||||||
|
|
||||||
s->enabled = enable;
|
s->enabled = enabled;
|
||||||
|
s->ratelimited = ratelimited;
|
||||||
|
|
||||||
/* Non-failing operations below */
|
/* Non-failing operations below */
|
||||||
switch (s->type) {
|
switch (s->type) {
|
||||||
@ -2379,7 +2527,7 @@ static int event_source_enable(sd_event_source *s, int enable) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
||||||
@ -2397,7 +2545,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (m == SD_EVENT_OFF)
|
if (m == SD_EVENT_OFF)
|
||||||
r = event_source_disable(s);
|
r = event_source_offline(s, m, s->ratelimited);
|
||||||
else {
|
else {
|
||||||
if (s->enabled != SD_EVENT_OFF) {
|
if (s->enabled != SD_EVENT_OFF) {
|
||||||
/* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the
|
/* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the
|
||||||
@ -2406,7 +2554,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = event_source_enable(s, m);
|
r = event_source_online(s, m, s->ratelimited);
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -2663,6 +2811,96 @@ _public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata)
|
|||||||
return ret;
|
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) {
|
static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) {
|
||||||
usec_t c;
|
usec_t c;
|
||||||
assert(e);
|
assert(e);
|
||||||
@ -2760,7 +2998,7 @@ static int event_arm_timer(
|
|||||||
d->needs_rearm = false;
|
d->needs_rearm = false;
|
||||||
|
|
||||||
a = prioq_peek(d->earliest);
|
a = prioq_peek(d->earliest);
|
||||||
if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) {
|
if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) {
|
||||||
|
|
||||||
if (d->fd < 0)
|
if (d->fd < 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -2779,7 +3017,7 @@ static int event_arm_timer(
|
|||||||
b = prioq_peek(d->latest);
|
b = prioq_peek(d->latest);
|
||||||
assert_se(b && b->enabled != SD_EVENT_OFF);
|
assert_se(b && b->enabled != SD_EVENT_OFF);
|
||||||
|
|
||||||
t = sleep_between(e, a->time.next, time_event_source_latest(b));
|
t = sleep_between(e, time_event_source_next(a), time_event_source_latest(b));
|
||||||
if (d->next == t)
|
if (d->next == t)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -2857,10 +3095,22 @@ static int process_timer(
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
s = prioq_peek(d->earliest);
|
s = prioq_peek(d->earliest);
|
||||||
if (!s ||
|
if (!s || time_event_source_next(s) > n)
|
||||||
s->time.next > n ||
|
break;
|
||||||
s->enabled == SD_EVENT_OFF ||
|
|
||||||
s->pending)
|
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)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
r = source_set_pending(s, true);
|
r = source_set_pending(s, true);
|
||||||
@ -2905,7 +3155,7 @@ static int process_child(sd_event *e) {
|
|||||||
if (s->pending)
|
if (s->pending)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (s->enabled == SD_EVENT_OFF)
|
if (event_source_is_offline(s))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (s->child.exited)
|
if (s->child.exited)
|
||||||
@ -2952,7 +3202,7 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
|
|||||||
if (s->pending)
|
if (s->pending)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (s->enabled == SD_EVENT_OFF)
|
if (event_source_is_offline(s))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!EVENT_SOURCE_WATCH_PIDFD(s))
|
if (!EVENT_SOURCE_WATCH_PIDFD(s))
|
||||||
@ -3112,7 +3362,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) {
|
LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) {
|
||||||
|
|
||||||
if (s->enabled == SD_EVENT_OFF)
|
if (event_source_is_offline(s))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = source_set_pending(s, true);
|
r = source_set_pending(s, true);
|
||||||
@ -3148,7 +3398,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) {
|
|||||||
* sources if IN_IGNORED or IN_UNMOUNT is set. */
|
* sources if IN_IGNORED or IN_UNMOUNT is set. */
|
||||||
LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) {
|
LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) {
|
||||||
|
|
||||||
if (s->enabled == SD_EVENT_OFF)
|
if (event_source_is_offline(s))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 &&
|
if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 &&
|
||||||
@ -3202,6 +3452,16 @@ static int source_dispatch(sd_event_source *s) {
|
|||||||
* callback might have invalidated/disconnected the event source. */
|
* callback might have invalidated/disconnected the event source. */
|
||||||
saved_event = sd_event_ref(s->event);
|
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)) {
|
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||||
r = source_set_pending(s, false);
|
r = source_set_pending(s, false);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -3215,7 +3475,7 @@ static int source_dispatch(sd_event_source *s) {
|
|||||||
* post sources as pending */
|
* post sources as pending */
|
||||||
|
|
||||||
SET_FOREACH(z, s->event->post_sources) {
|
SET_FOREACH(z, s->event->post_sources) {
|
||||||
if (z->enabled == SD_EVENT_OFF)
|
if (event_source_is_offline(z))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = source_set_pending(z, true);
|
r = source_set_pending(z, true);
|
||||||
@ -3335,7 +3595,7 @@ static int event_prepare(sd_event *e) {
|
|||||||
sd_event_source *s;
|
sd_event_source *s;
|
||||||
|
|
||||||
s = prioq_peek(e->prepare);
|
s = prioq_peek(e->prepare);
|
||||||
if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF)
|
if (!s || s->prepare_iteration == e->iteration || event_source_is_offline(s))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
s->prepare_iteration = e->iteration;
|
s->prepare_iteration = e->iteration;
|
||||||
@ -3370,18 +3630,17 @@ static int event_prepare(sd_event *e) {
|
|||||||
|
|
||||||
static int dispatch_exit(sd_event *e) {
|
static int dispatch_exit(sd_event *e) {
|
||||||
sd_event_source *p;
|
sd_event_source *p;
|
||||||
_cleanup_(sd_event_unrefp) sd_event *ref = NULL;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(e);
|
assert(e);
|
||||||
|
|
||||||
p = prioq_peek(e->exit);
|
p = prioq_peek(e->exit);
|
||||||
if (!p || p->enabled == SD_EVENT_OFF) {
|
if (!p || event_source_is_offline(p)) {
|
||||||
e->state = SD_EVENT_FINISHED;
|
e->state = SD_EVENT_FINISHED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref = sd_event_ref(e);
|
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
|
||||||
e->iteration++;
|
e->iteration++;
|
||||||
e->state = SD_EVENT_EXITING;
|
e->state = SD_EVENT_EXITING;
|
||||||
r = source_dispatch(p);
|
r = source_dispatch(p);
|
||||||
@ -3398,7 +3657,7 @@ static sd_event_source* event_next_pending(sd_event *e) {
|
|||||||
if (!p)
|
if (!p)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (p->enabled == SD_EVENT_OFF)
|
if (event_source_is_offline(p))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
@ -3477,6 +3736,9 @@ _public_ int sd_event_prepare(sd_event *e) {
|
|||||||
* syscalls */
|
* syscalls */
|
||||||
assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO);
|
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)
|
if (e->exit_requested)
|
||||||
goto pending;
|
goto pending;
|
||||||
|
|
||||||
@ -3682,9 +3944,8 @@ _public_ int sd_event_dispatch(sd_event *e) {
|
|||||||
|
|
||||||
p = event_next_pending(e);
|
p = event_next_pending(e);
|
||||||
if (p) {
|
if (p) {
|
||||||
_cleanup_(sd_event_unrefp) sd_event *ref = NULL;
|
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
|
||||||
|
|
||||||
ref = sd_event_ref(e);
|
|
||||||
e->state = SD_EVENT_RUNNING;
|
e->state = SD_EVENT_RUNNING;
|
||||||
r = source_dispatch(p);
|
r = source_dispatch(p);
|
||||||
e->state = SD_EVENT_INITIAL;
|
e->state = SD_EVENT_INITIAL;
|
||||||
@ -3718,29 +3979,32 @@ _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_FINISHED, -ESTALE);
|
||||||
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
|
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
|
||||||
|
|
||||||
if (e->profile_delays && e->last_run) {
|
if (e->profile_delays && e->last_run_usec != 0) {
|
||||||
usec_t this_run;
|
usec_t this_run;
|
||||||
unsigned l;
|
unsigned l;
|
||||||
|
|
||||||
this_run = now(CLOCK_MONOTONIC);
|
this_run = now(CLOCK_MONOTONIC);
|
||||||
|
|
||||||
l = u64log2(this_run - e->last_run);
|
l = u64log2(this_run - e->last_run_usec);
|
||||||
assert(l < ELEMENTSOF(e->delays));
|
assert(l < ELEMENTSOF(e->delays));
|
||||||
e->delays[l]++;
|
e->delays[l]++;
|
||||||
|
|
||||||
if (this_run - e->last_log >= 5*USEC_PER_SEC) {
|
if (this_run - e->last_log_usec >= 5*USEC_PER_SEC) {
|
||||||
event_log_delays(e);
|
event_log_delays(e);
|
||||||
e->last_log = this_run;
|
e->last_log_usec = 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);
|
r = sd_event_prepare(e);
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
/* There was nothing? Then wait... */
|
/* There was nothing? Then wait... */
|
||||||
r = sd_event_wait(e, timeout);
|
r = sd_event_wait(e, timeout);
|
||||||
|
|
||||||
if (e->profile_delays)
|
if (e->profile_delays)
|
||||||
e->last_run = now(CLOCK_MONOTONIC);
|
e->last_run_usec = now(CLOCK_MONOTONIC);
|
||||||
|
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
/* There's something now, then let's dispatch it */
|
/* There's something now, then let's dispatch it */
|
||||||
@ -3755,7 +4019,6 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_event_loop(sd_event *e) {
|
_public_ int sd_event_loop(sd_event *e) {
|
||||||
_cleanup_(sd_event_unrefp) sd_event *ref = NULL;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert_return(e, -EINVAL);
|
assert_return(e, -EINVAL);
|
||||||
@ -3763,7 +4026,7 @@ _public_ int sd_event_loop(sd_event *e) {
|
|||||||
assert_return(!event_pid_changed(e), -ECHILD);
|
assert_return(!event_pid_changed(e), -ECHILD);
|
||||||
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
|
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
|
||||||
|
|
||||||
ref = sd_event_ref(e);
|
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
|
||||||
|
|
||||||
while (e->state != SD_EVENT_FINISHED) {
|
while (e->state != SD_EVENT_FINISHED) {
|
||||||
r = sd_event_run(e, (uint64_t) -1);
|
r = sd_event_run(e, (uint64_t) -1);
|
||||||
@ -4008,3 +4271,53 @@ _public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) {
|
|||||||
s->exit_on_failure = b;
|
s->exit_on_failure = b;
|
||||||
return 1;
|
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,8 +589,100 @@ static void test_pidfd(void) {
|
|||||||
sd_event_unref(e);
|
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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
test_setup_logging(LOG_INFO);
|
test_setup_logging(LOG_DEBUG);
|
||||||
|
|
||||||
test_basic(true); /* test with pidfd */
|
test_basic(true); /* test with pidfd */
|
||||||
test_basic(false); /* test without pidfd */
|
test_basic(false); /* test without pidfd */
|
||||||
@ -603,5 +695,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
test_pidfd();
|
test_pidfd();
|
||||||
|
|
||||||
|
test_ratelimit();
|
||||||
|
|
||||||
return 0;
|
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);
|
(void) warn_file_is_world_accessible(sa->key_file, NULL, NULL, 0);
|
||||||
|
|
||||||
r = read_full_file_full(
|
r = read_full_file_full(
|
||||||
AT_FDCWD, sa->key_file,
|
AT_FDCWD, sa->key_file, UINT64_MAX, SIZE_MAX,
|
||||||
READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
|
READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
|
||||||
NULL, (char **) &key, &key_len);
|
NULL, (char **) &key, &key_len);
|
||||||
if (r < 0)
|
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);
|
(void) warn_file_is_world_accessible(filename, NULL, NULL, 0);
|
||||||
|
|
||||||
r = read_full_file_full(
|
r = read_full_file_full(
|
||||||
AT_FDCWD, filename,
|
AT_FDCWD, filename, UINT64_MAX, SIZE_MAX,
|
||||||
READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
|
READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
|
||||||
NULL, &key, &key_len);
|
NULL, &key, &key_len);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
@ -62,11 +62,9 @@ static struct DUID fallback_duid = { .type = DUID_TYPE_EN };
|
|||||||
DUID* link_get_duid(Link *link) {
|
DUID* link_get_duid(Link *link) {
|
||||||
if (link->network->duid.type != _DUID_TYPE_INVALID)
|
if (link->network->duid.type != _DUID_TYPE_INVALID)
|
||||||
return &link->network->duid;
|
return &link->network->duid;
|
||||||
else if (link->hw_addr.length == 0 &&
|
else if (link->hw_addr.length == 0 && IN_SET(link->manager->duid.type, DUID_TYPE_LLT, DUID_TYPE_LL))
|
||||||
(link->manager->duid.type == DUID_TYPE_LLT ||
|
/* Fallback to DUID that works without MAC address.
|
||||||
link->manager->duid.type == DUID_TYPE_LL))
|
* This is useful for tunnel devices without MAC address. */
|
||||||
/* Fallback to DUID that works without mac addresses.
|
|
||||||
* This is useful for tunnel devices without mac address. */
|
|
||||||
return &fallback_duid;
|
return &fallback_duid;
|
||||||
else
|
else
|
||||||
return &link->manager->duid;
|
return &link->manager->duid;
|
||||||
|
|||||||
@ -70,6 +70,10 @@ static void dhcp4_check_ready(Link *link) {
|
|||||||
return;
|
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);
|
link_check_ready(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,10 +1052,7 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
|
|||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case SD_DHCP_CLIENT_EVENT_STOP:
|
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");
|
log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address");
|
||||||
|
|
||||||
r = sd_ipv4ll_start(link->ipv4ll);
|
r = sd_ipv4ll_start(link->ipv4ll);
|
||||||
@ -1136,6 +1137,17 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
|
|||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
if (event < 0)
|
if (event < 0)
|
||||||
log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
|
log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
|
||||||
|
|||||||
@ -148,7 +148,7 @@ int ipv4ll_configure(Link *link) {
|
|||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
if (!link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4))
|
if (!link_ipv4ll_enabled(link))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!link->ipv4ll) {
|
if (!link->ipv4ll) {
|
||||||
|
|||||||
@ -55,9 +55,8 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "vrf.h"
|
#include "vrf.h"
|
||||||
|
|
||||||
bool link_ipv4ll_enabled(Link *link, AddressFamily mask) {
|
bool link_ipv4ll_enabled(Link *link) {
|
||||||
assert(link);
|
assert(link);
|
||||||
assert((mask & ~(ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) == 0);
|
|
||||||
|
|
||||||
if (link->flags & IFF_LOOPBACK)
|
if (link->flags & IFF_LOOPBACK)
|
||||||
return false;
|
return false;
|
||||||
@ -80,7 +79,7 @@ bool link_ipv4ll_enabled(Link *link, AddressFamily mask) {
|
|||||||
if (link->network->bond)
|
if (link->network->bond)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return link->network->link_local & mask;
|
return link->network->link_local & ADDRESS_FAMILY_IPV4;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool link_ipv6ll_enabled(Link *link) {
|
bool link_ipv6ll_enabled(Link *link) {
|
||||||
@ -734,77 +733,51 @@ void link_check_ready(Link *link) {
|
|||||||
if (link->state == LINK_STATE_CONFIGURED)
|
if (link->state == LINK_STATE_CONFIGURED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (link->state != LINK_STATE_CONFIGURING) {
|
if (link->state != LINK_STATE_CONFIGURING)
|
||||||
log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
|
return (void) log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!link->network)
|
if (!link->network)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!link->addresses_configured) {
|
if (!link->addresses_configured)
|
||||||
log_link_debug(link, "%s(): static addresses are not configured.", __func__);
|
return (void) log_link_debug(link, "%s(): static addresses are not configured.", __func__);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!link->neighbors_configured) {
|
if (!link->neighbors_configured)
|
||||||
log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
|
return (void) log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SET_FOREACH(a, link->addresses)
|
SET_FOREACH(a, link->addresses)
|
||||||
if (!address_is_ready(a)) {
|
if (!address_is_ready(a)) {
|
||||||
_cleanup_free_ char *str = NULL;
|
_cleanup_free_ char *str = NULL;
|
||||||
|
|
||||||
(void) in_addr_to_string(a->family, &a->in_addr, &str);
|
(void) in_addr_to_string(a->family, &a->in_addr, &str);
|
||||||
log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen);
|
return (void) log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!link->static_routes_configured) {
|
if (!link->static_routes_configured)
|
||||||
log_link_debug(link, "%s(): static routes are not configured.", __func__);
|
return (void) log_link_debug(link, "%s(): static routes are not configured.", __func__);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!link->static_nexthops_configured) {
|
if (!link->static_nexthops_configured)
|
||||||
log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
|
return (void) log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!link->routing_policy_rules_configured) {
|
if (!link->routing_policy_rules_configured)
|
||||||
log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
|
return (void) log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!link->tc_configured) {
|
if (!link->tc_configured)
|
||||||
log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
|
return (void) log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!link->sr_iov_configured) {
|
if (!link->sr_iov_configured)
|
||||||
log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
|
return (void) log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!link->bridge_mdb_configured) {
|
if (!link->bridge_mdb_configured)
|
||||||
log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__);
|
return (void) log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (link_has_carrier(link) || !link->network->configure_without_carrier) {
|
if (link_has_carrier(link) || !link->network->configure_without_carrier) {
|
||||||
bool has_ndisc_address = false;
|
bool has_ndisc_address = false;
|
||||||
NDiscAddress *n;
|
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) &&
|
if (link_ipv6ll_enabled(link) &&
|
||||||
in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) {
|
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 (void) log_link_debug(link, "%s(): IPv6LL is not configured.", __func__);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SET_FOREACH(n, link->ndisc_addresses)
|
SET_FOREACH(n, link->ndisc_addresses)
|
||||||
if (!n->marked) {
|
if (!n->marked) {
|
||||||
@ -812,28 +785,26 @@ void link_check_ready(Link *link) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) &&
|
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_ipv4ll_enabled(link)) &&
|
||||||
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
|
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
|
||||||
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
|
!link->ipv4ll_address_configured)
|
||||||
log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no dynamic address is assigned yet.", __func__);
|
/* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
|
||||||
return;
|
return (void) log_link_debug(link, "%s(): DHCP4, DHCP6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
|
||||||
}
|
|
||||||
|
|
||||||
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) || link_ipv6_accept_ra_enabled(link)) {
|
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_configured &&
|
if (!link->dhcp4_configured &&
|
||||||
!(link->dhcp6_address_configured && link->dhcp6_route_configured) &&
|
!(link->dhcp6_address_configured && link->dhcp6_route_configured) &&
|
||||||
!(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) &&
|
!(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) &&
|
||||||
!(link->ndisc_addresses_configured && link->ndisc_routes_configured) &&
|
!(link->ndisc_addresses_configured && link->ndisc_routes_configured) &&
|
||||||
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
|
!link->ipv4ll_address_configured)
|
||||||
/* When DHCP or RA is enabled, at least one protocol must provide an address, or
|
/* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */
|
||||||
* an IPv4ll fallback address must be configured. */
|
return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
||||||
log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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",
|
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",
|
||||||
__func__,
|
__func__,
|
||||||
yes_no(link->dhcp4_configured),
|
yes_no(link->dhcp4_configured),
|
||||||
|
yes_no(link->ipv4ll_address_configured),
|
||||||
yes_no(link->dhcp6_address_configured),
|
yes_no(link->dhcp6_address_configured),
|
||||||
yes_no(link->dhcp6_route_configured),
|
yes_no(link->dhcp6_route_configured),
|
||||||
yes_no(link->dhcp6_pd_address_configured),
|
yes_no(link->dhcp6_pd_address_configured),
|
||||||
@ -844,8 +815,6 @@ void link_check_ready(Link *link) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
link_enter_configured(link);
|
link_enter_configured(link);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_static_configs(Link *link) {
|
static int link_set_static_configs(Link *link) {
|
||||||
@ -1230,22 +1199,19 @@ static int link_acquire_ipv4_conf(Link *link) {
|
|||||||
assert(link->manager);
|
assert(link->manager);
|
||||||
assert(link->manager->event);
|
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) {
|
if (link->dhcp_client) {
|
||||||
log_link_debug(link, "Acquiring DHCPv4 lease");
|
log_link_debug(link, "Acquiring DHCPv4 lease");
|
||||||
|
|
||||||
r = sd_dhcp_client_start(link->dhcp_client);
|
r = sd_dhcp_client_start(link->dhcp_client);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
|
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;
|
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);
|
int link_set_mtu(Link *link, uint32_t mtu);
|
||||||
|
|
||||||
bool link_ipv4ll_enabled(Link *link, AddressFamily mask);
|
bool link_ipv4ll_enabled(Link *link);
|
||||||
|
|
||||||
int link_stop_engines(Link *link, bool may_keep_dhcp);
|
int link_stop_engines(Link *link, bool may_keep_dhcp);
|
||||||
|
|
||||||
|
|||||||
@ -210,13 +210,6 @@ int network_verify(Network *network) {
|
|||||||
if (network->link_local < 0)
|
if (network->link_local < 0)
|
||||||
network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
|
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 */
|
/* IPMasquerade=yes implies IPForward=yes */
|
||||||
if (network->ip_masquerade)
|
if (network->ip_masquerade)
|
||||||
network->ip_forward |= ADDRESS_FAMILY_IPV4;
|
network->ip_forward |= ADDRESS_FAMILY_IPV4;
|
||||||
|
|||||||
@ -15,15 +15,6 @@ static const char* const address_family_table[_ADDRESS_FAMILY_MAX] = {
|
|||||||
[ADDRESS_FAMILY_IPV6] = "ipv6",
|
[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] = {
|
static const char* const routing_policy_rule_address_family_table[_ADDRESS_FAMILY_MAX] = {
|
||||||
[ADDRESS_FAMILY_YES] = "both",
|
[ADDRESS_FAMILY_YES] = "both",
|
||||||
[ADDRESS_FAMILY_IPV4] = "ipv4",
|
[ADDRESS_FAMILY_IPV4] = "ipv4",
|
||||||
@ -47,7 +38,15 @@ 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);
|
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(address_family, AddressFamily, ADDRESS_FAMILY_YES);
|
||||||
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(link_local_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(routing_policy_rule_address_family, AddressFamily);
|
DEFINE_STRING_TABLE_LOOKUP(routing_policy_rule_address_family, AddressFamily);
|
||||||
DEFINE_STRING_TABLE_LOOKUP(duplicate_address_detection_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,
|
DEFINE_CONFIG_PARSE_ENUM(config_parse_link_local_address_family, link_local_address_family,
|
||||||
|
|||||||
@ -16,8 +16,6 @@ typedef enum AddressFamily {
|
|||||||
ADDRESS_FAMILY_IPV4 = 1 << 0,
|
ADDRESS_FAMILY_IPV4 = 1 << 0,
|
||||||
ADDRESS_FAMILY_IPV6 = 1 << 1,
|
ADDRESS_FAMILY_IPV6 = 1 << 1,
|
||||||
ADDRESS_FAMILY_YES = ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6,
|
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_MAX,
|
||||||
_ADDRESS_FAMILY_INVALID = -1,
|
_ADDRESS_FAMILY_INVALID = -1,
|
||||||
} AddressFamily;
|
} AddressFamily;
|
||||||
@ -34,7 +32,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_address_family_with_kernel);
|
|||||||
const char *address_family_to_string(AddressFamily b) _const_;
|
const char *address_family_to_string(AddressFamily b) _const_;
|
||||||
AddressFamily address_family_from_string(const char *s) _pure_;
|
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_;
|
AddressFamily link_local_address_family_from_string(const char *s) _pure_;
|
||||||
|
|
||||||
const char *routing_policy_rule_address_family_to_string(AddressFamily b) _const_;
|
const char *routing_policy_rule_address_family_to_string(AddressFamily b) _const_;
|
||||||
|
|||||||
@ -1589,7 +1589,10 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
r = read_full_file_full(AT_FDCWD, j ?: p, flags, NULL, &data, &size);
|
r = read_full_file_full(AT_FDCWD, j ?: p, UINT64_MAX, SIZE_MAX,
|
||||||
|
flags,
|
||||||
|
NULL,
|
||||||
|
&data, &size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read credential '%s': %m", j ?: p);
|
return log_error_errno(r, "Failed to read credential '%s': %m", j ?: p);
|
||||||
|
|
||||||
|
|||||||
@ -3621,7 +3621,11 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
_cleanup_(erase_and_freep) char *k = NULL;
|
_cleanup_(erase_and_freep) char *k = NULL;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
|
||||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_SECURE|READ_FULL_FILE_CONNECT_SOCKET, NULL, &k, &n);
|
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);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read key file '%s': %m", optarg);
|
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 (verity->root_hash && !verity->root_hash_sig) {
|
||||||
if (root_hash_sig_path) {
|
if (root_hash_sig_path) {
|
||||||
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
|
r = read_full_file(root_hash_sig_path, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -2131,7 +2131,7 @@ int verity_settings_load(
|
|||||||
if (!p)
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = read_full_file_full(AT_FDCWD, p, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
|
r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
return r;
|
return r;
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
@ -2145,7 +2145,7 @@ int verity_settings_load(
|
|||||||
if (!p)
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = read_full_file_full(AT_FDCWD, p, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
|
r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
return r;
|
return r;
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
|
|||||||
@ -3195,7 +3195,7 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags fla
|
|||||||
if (f)
|
if (f)
|
||||||
r = read_full_stream(f, &text, NULL);
|
r = read_full_stream(f, &text, NULL);
|
||||||
else if (path)
|
else if (path)
|
||||||
r = read_full_file_full(dir_fd, path, 0, NULL, &text, NULL);
|
r = read_full_file_full(dir_fd, path, UINT64_MAX, SIZE_MAX, 0, NULL, &text, NULL);
|
||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
@ -40,6 +40,8 @@ enum {
|
|||||||
SD_DHCP_CLIENT_EVENT_EXPIRED = 3,
|
SD_DHCP_CLIENT_EVENT_EXPIRED = 3,
|
||||||
SD_DHCP_CLIENT_EVENT_RENEW = 4,
|
SD_DHCP_CLIENT_EVENT_RENEW = 4,
|
||||||
SD_DHCP_CLIENT_EVENT_SELECTING = 5,
|
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 {
|
enum {
|
||||||
|
|||||||
@ -162,6 +162,9 @@ 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_set_floating(sd_event_source *s, int b);
|
||||||
int sd_event_source_get_exit_on_failure(sd_event_source *s);
|
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_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. */
|
/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
|
||||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);
|
_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);
|
_exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_se(read_full_file_full(AT_FDCWD, j, 0, NULL, &data, &size) == -ENXIO);
|
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, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0);
|
assert_se(read_full_file_full(AT_FDCWD, j, UINT64_MAX, SIZE_MAX, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0);
|
||||||
assert_se(size == strlen(TEST_STR));
|
assert_se(size == strlen(TEST_STR));
|
||||||
assert_se(streq(data, TEST_STR));
|
assert_se(streq(data, TEST_STR));
|
||||||
|
|
||||||
@ -920,6 +920,50 @@ static void test_read_full_file_socket(void) {
|
|||||||
#undef TEST_STR
|
#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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
test_setup_logging(LOG_DEBUG);
|
test_setup_logging(LOG_DEBUG);
|
||||||
|
|
||||||
@ -946,6 +990,7 @@ int main(int argc, char *argv[]) {
|
|||||||
test_read_line4();
|
test_read_line4();
|
||||||
test_read_nul_string();
|
test_read_nul_string();
|
||||||
test_read_full_file_socket();
|
test_read_full_file_socket();
|
||||||
|
test_read_full_file_offset_size();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,7 +100,11 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", argv[6]);
|
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", argv[6]);
|
||||||
} else {
|
} else {
|
||||||
r = read_full_file_full(AT_FDCWD, argv[6], READ_FULL_FILE_CONNECT_SOCKET, NULL, &hash_sig, &hash_sig_size);
|
r = read_full_file_full(
|
||||||
|
AT_FDCWD, argv[6], UINT64_MAX, SIZE_MAX,
|
||||||
|
READ_FULL_FILE_CONNECT_SOCKET,
|
||||||
|
NULL,
|
||||||
|
&hash_sig, &hash_sig_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read root hash signature: %m");
|
return log_error_errno(r, "Failed to read root hash signature: %m");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,5 +4,4 @@ Name=veth99
|
|||||||
[Network]
|
[Network]
|
||||||
DHCP=yes
|
DHCP=yes
|
||||||
IPv6AcceptRA=yes
|
IPv6AcceptRA=yes
|
||||||
LinkLocalAddressing=yes
|
|
||||||
VRF=vrf99
|
VRF=vrf99
|
||||||
|
|||||||
@ -3,5 +3,5 @@ Name=veth99
|
|||||||
|
|
||||||
[Network]
|
[Network]
|
||||||
DHCP=ipv4
|
DHCP=ipv4
|
||||||
LinkLocalAddressing=fallback
|
LinkLocalAddressing=yes
|
||||||
IPv6AcceptRA=no
|
IPv6AcceptRA=no
|
||||||
@ -3,7 +3,7 @@ Name=veth99
|
|||||||
|
|
||||||
[Network]
|
[Network]
|
||||||
DHCP=ipv4
|
DHCP=ipv4
|
||||||
LinkLocalAddressing=fallback
|
LinkLocalAddressing=yes
|
||||||
IPv6AcceptRA=no
|
IPv6AcceptRA=no
|
||||||
|
|
||||||
[DHCPv4]
|
[DHCPv4]
|
||||||
@ -3428,8 +3428,8 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
|||||||
'dhcp-client-use-dns-yes.network',
|
'dhcp-client-use-dns-yes.network',
|
||||||
'dhcp-client-use-domains.network',
|
'dhcp-client-use-domains.network',
|
||||||
'dhcp-client-vrf.network',
|
'dhcp-client-vrf.network',
|
||||||
'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
|
'dhcp-client-with-ipv4ll-with-dhcp-server.network',
|
||||||
'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
|
'dhcp-client-with-ipv4ll-without-dhcp-server.network',
|
||||||
'dhcp-client-with-static-address.network',
|
'dhcp-client-with-static-address.network',
|
||||||
'dhcp-client.network',
|
'dhcp-client.network',
|
||||||
'dhcp-server-decline.network',
|
'dhcp-server-decline.network',
|
||||||
@ -3925,7 +3925,6 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
|||||||
print('## ip address show vrf vrf99')
|
print('## ip address show vrf vrf99')
|
||||||
output = check_output('ip address show vrf vrf99')
|
output = check_output('ip address show vrf vrf99')
|
||||||
print(output)
|
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, '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 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
|
||||||
self.assertRegex(output, 'inet6 .* scope link')
|
self.assertRegex(output, 'inet6 .* scope link')
|
||||||
@ -3933,7 +3932,6 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
|||||||
print('## ip address show dev veth99')
|
print('## ip address show dev veth99')
|
||||||
output = check_output('ip address show dev veth99')
|
output = check_output('ip address show dev veth99')
|
||||||
print(output)
|
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, '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 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
|
||||||
self.assertRegex(output, 'inet6 .* scope link')
|
self.assertRegex(output, 'inet6 .* scope link')
|
||||||
@ -3942,7 +3940,6 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
|||||||
output = check_output('ip route show vrf vrf99')
|
output = check_output('ip route show vrf vrf99')
|
||||||
print(output)
|
print(output)
|
||||||
self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
|
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 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.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')
|
self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
|
||||||
@ -3995,9 +3992,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
|||||||
print(output)
|
print(output)
|
||||||
self.assertRegex(output, 'onlink')
|
self.assertRegex(output, 'onlink')
|
||||||
|
|
||||||
def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
|
def test_dhcp_client_with_ipv4ll_with_dhcp_server(self):
|
||||||
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
|
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
|
||||||
'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
|
'dhcp-client-with-ipv4ll-with-dhcp-server.network')
|
||||||
start_networkd()
|
start_networkd()
|
||||||
self.wait_online(['veth-peer:carrier'])
|
self.wait_online(['veth-peer:carrier'])
|
||||||
start_dnsmasq(lease_time='2m')
|
start_dnsmasq(lease_time='2m')
|
||||||
@ -4032,9 +4029,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
|
|||||||
|
|
||||||
search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
|
search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
|
||||||
|
|
||||||
def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
|
def test_dhcp_client_with_ipv4ll_without_dhcp_server(self):
|
||||||
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
|
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
|
||||||
'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
|
'dhcp-client-with-ipv4ll-without-dhcp-server.network')
|
||||||
start_networkd()
|
start_networkd()
|
||||||
self.wait_online(['veth99:degraded', 'veth-peer:routable'])
|
self.wait_online(['veth99:degraded', 'veth-peer:routable'])
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user