1
0
mirror of https://github.com/systemd/systemd synced 2025-12-28 20:04:45 +01:00

Compare commits

..

No commits in common. "0a67dd8310065a35a2fba2229b89ea0ab3e651fe" and "e9eec8b5d2c106c5dd51382a155e6045c7c17c1a" have entirely different histories.

48 changed files with 421 additions and 1104 deletions

3
TODO
View File

@ -76,6 +76,9 @@ Features:
* make use of new glibc 2.32 APIs sigabbrev_np() and strerrorname_np().
* cryptsetup: if keyfile specified in crypttab is AF_UNIX socket, connect to it
and read from it (like we do elsewhere with READ_FULL_FILE_CONNECT_SOCKET)
* when main nspawn supervisor process gets suspended due to SIGSTOP/SIGTTOU or
so, freeze the payload too.

View File

@ -53,36 +53,25 @@
it is opened as a LUKS device; otherwise, it is assumed to be in
raw dm-crypt (plain mode) format.</para>
<para>The four fields of <filename>/etc/crypttab</filename> are defined as follows:</para>
<para>The first field contains the name of the resulting encrypted volume; its block device is set up
below <filename>/dev/mapper/</filename>.</para>
<orderedlist>
<para>The second field contains a path to the underlying block
device or file, or a specification of a block device via
<literal>UUID=</literal> followed by the UUID.</para>
<listitem><para>The first field contains the name of the resulting volume with decrypted data; its
block device is set up below <filename>/dev/mapper/</filename>.</para></listitem>
<para>The third field specifies an absolute path to a file with the encryption key. Optionally,
the path may be followed by <literal>:</literal> and an fstab device specification (e.g. starting with
<literal>LABEL=</literal> or similar); in which case the path is taken relative to the device file system
root. If the field is not present or is <literal>none</literal> or <literal>-</literal>, a key file
named after the volume to unlock (i.e. the first column of the line), suffixed with
<filename>.key</filename> is automatically loaded from the <filename>/etc/cryptsetup-keys.d/</filename>
and <filename>/run/cryptsetup-keys.d/</filename> directories, if present. Otherwise, the password has to
be manually entered during system boot. For swap encryption, <filename>/dev/urandom</filename> may be
used as key file.</para>
<listitem><para>The second field contains a path to the underlying block
device or file, or a specification of a block device via
<literal>UUID=</literal> followed by the UUID.</para></listitem>
<listitem><para>The third field specifies an absolute path to a file with the encryption
key. Optionally, the path may be followed by <literal>:</literal> and an fstab device specification
(e.g. starting with <literal>LABEL=</literal> or similar); in which case the path is taken relative to
the device file system root. If the field is not present or is <literal>none</literal> or
<literal>-</literal>, a key file named after the volume to unlock (i.e. the first column of the line),
suffixed with <filename>.key</filename> is automatically loaded from the
<filename>/etc/cryptsetup-keys.d/</filename> and <filename>/run/cryptsetup-keys.d/</filename>
directories, if present. Otherwise, the password has to be manually entered during system boot. For
swap encryption, <filename>/dev/urandom</filename> may be used as key file, resulting in a randomized
key.</para>
<para>If the specified key file path refers to an <constant>AF_UNIX</constant> stream socket in the
file system, the key is acquired by connecting to the socket and reading it from the connection. This
allows the implementation of a service to provide key information dynamically, at the moment when it is
needed. For details see below.</para></listitem>
<listitem><para>The fourth field, if present, is a comma-delimited list of options. The suppported
options are listed below.</para></listitem>
</orderedlist>
<para>The fourth field, if present, is a comma-delimited list of
options. The following options are recognized:</para>
<variablelist class='fstab-options'>
@ -510,34 +499,6 @@
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
<title><constant>AF_UNIX</constant> Key Files</title>
<para>If the key file path (as specified in the third column of <filename>/etc/crypttab</filename>
entries, see above) refers to an <constant>AF_UNIX</constant> stream socket in the file system, the key
is acquired by connecting to the socket and reading the key from the connection. The connection is made
from an <constant>AF_UNIX</constant> socket name in the abstract namespace, see <citerefentry
project='man-pages'><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
details. The source socket name is chosen according the following format:</para>
<programlisting><constant>NUL</constant> <replaceable>RANDOM</replaceable> <literal>/cryptsetup/</literal> <replaceable>VOLUME</replaceable></programlisting>
<para>In other words: a <constant>NUL</constant> byte (as required for abstract namespace sockets),
followed by a random string (consisting of alphabenumeric characters only), followed by the literal
string <literal>/cryptsetup/</literal>, followed by the name of the volume to acquire they key
for. Example (for a volume <literal>myvol</literal>):</para>
<example><programlisting>\0d7067f78d9827418/cryptsetup/myvol</programlisting></example>
<para>Services listening on the <constant>AF_UNIX</constant> stream socket may query the source socket
name with <citerefentry
project='man-pages'><refentrytitle>getpeername</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
and use it to determine which key to send, allowing a single listening socket to serve keys for a
multitude of volumes. If the PKCS#11 logic is used (see below) the socket source name is picked in
identical fashion, except that the literal string <literal>/cryptsetup-pkcs11/</literal> is used. This is
done so that services providing key material know that not a secret key is requested but an encrypted key
that will be decrypted via the PKCS#11 logic to acquire the final secret key.</para>
</refsect1>
<refsect1>
<title>Examples</title>
<example>
@ -568,6 +529,7 @@ external /dev/sda3 keyfile:LABEL=keydev keyfile-timeout=10s,cipher=xchac
<para>A few notes on the above:</para>
<itemizedlist>
<listitem><para>We use RSA (and not ECC), since Yubikeys support PKCS#11 Decrypt() only for RSA keys</para></listitem>
<listitem><para>We use RSA2048, which is the longest key size current Yubikeys support</para></listitem>
<listitem><para>LUKS key size must be shorter than 2048bit due to RSA padding, hence we use 128 bytes</para></listitem>
<listitem><para>We use Yubikey key slot 9d, since that's apparently the keyslot to use for decryption purposes,

View File

@ -582,10 +582,6 @@ manpages = [
'SD_EVENT_PRIORITY_NORMAL',
'sd_event_source_get_priority'],
''],
['sd_event_source_set_ratelimit',
'3',
['sd_event_source_get_ratelimit', 'sd_event_source_is_ratelimited'],
''],
['sd_event_source_set_userdata', '3', ['sd_event_source_get_userdata'], ''],
['sd_event_source_unref',
'3',

View File

@ -56,7 +56,6 @@
<citerefentry><refentrytitle>sd_event_source_get_pending</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_source_set_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_source_set_ratelimit</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
@ -148,7 +147,6 @@
<citerefentry><refentrytitle>sd_event_source_get_pending</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_source_set_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_source_set_ratelimit</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,

View File

@ -147,8 +147,7 @@
<citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_add_inotify</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_source_set_ratelimit</refentrytitle><manvolnum>3</manvolnum></citerefentry>
<citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>

View File

@ -1,148 +0,0 @@
<?xml version='1.0'?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="sd_event_source_set_ratelimit" xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>sd_event_source_set_ratelimit</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>sd_event_source_set_ratelimit</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>sd_event_source_set_ratelimit</refname>
<refname>sd_event_source_get_ratelimit</refname>
<refname>sd_event_source_is_ratelimited</refname>
<refpurpose>Configure rate limiting on event sources</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-event.h&gt;</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>

View File

@ -68,8 +68,8 @@
<term><option>--key=</option></term>
<listitem><para>Specify the path to a file or <constant>AF_UNIX</constant> stream socket to read the
secret server key corresponding to the certificate specified with <option>--cert=</option> from. The
key must be in PEM format.</para></listitem>
server key corresponding to the certificate specified with <option>--cert=</option> from. The key
must be in PEM format.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -180,7 +180,7 @@
<varlistentry>
<term><option>--key=</option></term>
<listitem><para>Takes a path to a SSL secret key file in PEM format. Defaults to
<listitem><para> Takes a path to a SSL key file in PEM format. Defaults to
<filename>&CERTIFICATE_ROOT;/private/journal-remote.pem</filename>. This option can be used with
<option>--listen-https=</option>. If the path refers to an <constant>AF_UNIX</constant> stream socket
in the file system a connection is made to it and the key read from it.</para></listitem>

View File

@ -364,15 +364,17 @@
<varlistentry>
<term><varname>LinkLocalAddressing=</varname></term>
<listitem>
<para>Enables link-local address autoconfiguration. Accepts <option>yes</option>,
<option>no</option>, <option>ipv4</option>, and <option>ipv6</option>. An IPv6 link-local address
is configured when <option>yes</option> or <option>ipv6</option>. An IPv4 link-local address is
configured when <option>yes</option> or <option>ipv4</option> and when DHCPv4 autoconfiguration
has been unsuccessful for some time. (IPv4 link-local address autoconfiguration will usually
happen in parallel with repeated attempts to acquire a DHCPv4 lease).</para>
<para>Defaults to <option>no</option> when <varname>Bridge=yes</varname> is set, and
<option>ipv6</option> otherwise.</para>
<para>Enables link-local address autoconfiguration. Accepts <literal>yes</literal>,
<literal>no</literal>, <literal>ipv4</literal>, <literal>ipv6</literal>,
<literal>fallback</literal>, or <literal>ipv4-fallback</literal>. If
<literal>fallback</literal> or <literal>ipv4-fallback</literal> is specified, then an IPv4
link-local address is configured only when DHCPv4 fails. If <literal>fallback</literal>,
an IPv6 link-local address is always configured, and if <literal>ipv4-fallback</literal>,
the address is not configured. Note that, the fallback mechanism works only when DHCPv4
client is enabled, that is, it requires <literal>DHCP=yes</literal> or
<literal>DHCP=ipv4</literal>. If <varname>Bridge=</varname> is set, defaults to
<literal>no</literal>, and if not, defaults to <literal>ipv6</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
@ -1662,10 +1664,9 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
<term><varname>MaxAttempts=</varname></term>
<listitem>
<para>Specifies how many times the DHCPv4 client configuration should be attempted. Takes a
number or <literal>infinity</literal>. Defaults to <literal>infinity</literal>. Note that the
time between retries is increased exponentially, up to approximately one per minute, so the
network will not be overloaded even if this number is high. The default is suitable in most
circumstances.</para>
number or <literal>infinity</literal>. Defaults to <literal>infinity</literal>.
Note that the time between retries is increased exponentially, so the network will not be
overloaded even if this number is high.</para>
</listitem>
</varlistentry>

View File

@ -472,13 +472,12 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
int read_full_stream_full(
FILE *f,
const char *filename,
uint64_t offset,
size_t size,
ReadFullFileFlags flags,
char **ret_contents,
size_t *ret_size) {
_cleanup_free_ char *buf = NULL;
struct stat st;
size_t n, n_next, l;
int fd, r;
@ -486,45 +485,32 @@ int read_full_stream_full(
assert(ret_contents);
assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
if (offset != UINT64_MAX && offset > LONG_MAX)
return -ERANGE;
n_next = size != SIZE_MAX ? size : LINE_MAX; /* Start size */
n_next = LINE_MAX; /* Start size */
fd = fileno(f);
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see
* fmemopen()), let's optimize our buffering */
struct stat st;
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's
* optimize our buffering */
if (fstat(fd, &st) < 0)
return -errno;
if (S_ISREG(st.st_mode)) {
if (size == SIZE_MAX) {
uint64_t rsize =
LESS_BY((uint64_t) st.st_size, offset == UINT64_MAX ? 0 : offset);
/* Safety check */
if (rsize > READ_FULL_BYTES_MAX)
return -E2BIG;
/* Safety check */
if (st.st_size > READ_FULL_BYTES_MAX)
return -E2BIG;
/* Start with the right file size. Note that we increase the size to read
* here by one, so that the first read attempt already makes us notice the
* EOF. If the reported size of the file is zero, we avoid this logic
* however, since quite likely it might be a virtual file in procfs that all
* report a zero file size. */
if (st.st_size > 0)
n_next = rsize + 1;
}
/* Start with the right file size. Note that we increase the size
* to read here by one, so that the first read attempt already
* makes us notice the EOF. */
if (st.st_size > 0)
n_next = st.st_size + 1;
if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
(void) warn_file_is_world_accessible(filename, &st, NULL, 0);
}
}
if (offset != UINT64_MAX && fseek(f, offset, SEEK_SET) < 0)
return -errno;
n = l = 0;
for (;;) {
char *t;
@ -561,11 +547,6 @@ int read_full_stream_full(
if (feof(f))
break;
if (size != SIZE_MAX) { /* If we got asked to read some specific size, we already sized the buffer right, hence leave */
assert(l == size);
break;
}
assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
/* Safety check */
@ -624,18 +605,15 @@ finalize:
int read_full_file_full(
int dir_fd,
const char *filename,
uint64_t offset,
size_t size,
ReadFullFileFlags flags,
const char *bind_name,
char **ret_contents,
size_t *ret_size) {
char **contents, size_t *size) {
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(filename);
assert(ret_contents);
assert(contents);
r = xfopenat(dir_fd, filename, "re", 0, &f);
if (r < 0) {
@ -650,10 +628,6 @@ int read_full_file_full(
if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
return -ENXIO;
/* Seeking is not supported on AF_UNIX sockets */
if (offset != UINT64_MAX)
return -ESPIPE;
if (dir_fd == AT_FDCWD)
r = sockaddr_un_set_path(&sa.un, filename);
else {
@ -707,7 +681,7 @@ int read_full_file_full(
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
return read_full_stream_full(f, filename, flags, contents, size);
}
int executable_is_script(const char *path, char **interpreter) {

View File

@ -60,14 +60,14 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
int read_one_line_file(const char *filename, char **line);
int read_full_file_full(int dir_fd, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, const char *bind_name, char **ret_contents, size_t *ret_size);
static inline int read_full_file(const char *filename, char **ret_contents, size_t *ret_size) {
return read_full_file_full(AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size);
int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, const char *bind_name, char **contents, size_t *size);
static inline int read_full_file(const char *filename, char **contents, size_t *size) {
return read_full_file_full(AT_FDCWD, filename, 0, NULL, contents, size);
}
int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size);
int read_full_stream_full(FILE *f, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, char **ret_contents, size_t *ret_size);
static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_size) {
return read_full_stream_full(f, NULL, UINT64_MAX, SIZE_MAX, 0, ret_contents, ret_size);
int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
static inline int read_full_stream(FILE *f, char **contents, size_t *size) {
return read_full_stream_full(f, NULL, 0, contents, size);
}
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);

View File

@ -28,12 +28,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
scope type name##_from_string(const char *s) { \
int b; \
if (!s) \
return -1; \
int b = parse_boolean(s); \
b = parse_boolean(s); \
if (b == 0) \
return (type) 0; \
if (b > 0) \
else if (b > 0) \
return yes; \
return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
}

View File

@ -2576,7 +2576,7 @@ static int acquire_credentials(
if (source)
r = read_full_file_full(AT_FDCWD, source, UINT64_MAX, SIZE_MAX, flags, bindname, &data, &size);
r = read_full_file_full(AT_FDCWD, source, flags, bindname, &data, &size);
else
r = -ENOENT;
if (r == -ENOENT &&

View File

@ -1855,12 +1855,6 @@ static void mount_enumerate(Manager *m) {
goto fail;
}
r = sd_event_source_set_ratelimit(m->mount_event_source, 1 * USEC_PER_SEC, 5);
if (r < 0) {
log_error_errno(r, "Failed to enable rate limit for mount events: %m");
goto fail;
}
(void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch");
}

View File

@ -1,18 +1,29 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <unistd.h>
#include "cryptsetup-keyfile.h"
#include "fileio.h"
#include "fd-util.h"
#include "format-util.h"
#include "memory-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "strv.h"
int find_key_file(
#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
int load_key_file(
const char *key_file,
char **search_path,
const char *bindname,
size_t key_file_size,
uint64_t key_file_offset,
void **ret_key,
size_t *ret_key_size) {
char **i;
_cleanup_(erase_and_freep) char *buffer = NULL;
_cleanup_free_ char *discovered_path = NULL;
_cleanup_close_ int fd = -1;
ssize_t n;
int r;
assert(key_file);
@ -20,38 +31,80 @@ int find_key_file(
assert(ret_key_size);
if (strv_isempty(search_path) || path_is_absolute(key_file)) {
fd = open(key_file, O_RDONLY|O_CLOEXEC);
if (fd < 0)
return log_error_errno(errno, "Failed to load key file '%s': %m", key_file);
} else {
char **i;
r = read_full_file_full(
AT_FDCWD, key_file, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
bindname,
(char**) ret_key, ret_key_size);
STRV_FOREACH(i, search_path) {
_cleanup_free_ char *joined;
joined = path_join(*i, key_file);
if (!joined)
return log_oom();
fd = open(joined, O_RDONLY|O_CLOEXEC);
if (fd >= 0) {
discovered_path = TAKE_PTR(joined);
break;
}
if (errno != ENOENT)
return log_error_errno(errno, "Failed to load key file '%s': %m", joined);
}
if (!discovered_path) {
/* Search path supplied, but file not found, report by returning NULL, but not failing */
*ret_key = NULL;
*ret_key_size = 0;
return 0;
}
assert(fd >= 0);
key_file = discovered_path;
}
if (key_file_size == 0) {
struct stat st;
if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file);
r = stat_verify_regular(&st);
if (r < 0)
return log_error_errno(r, "Failed to load key file '%s': %m", key_file);
return log_error_errno(r, "Key file is not a regular file: %m");
return 1;
if (st.st_size == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
"Key file larger (%s) than allowed maximum size (%s), refusing.",
format_bytes(buf1, sizeof(buf1), st.st_size),
format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
}
if (key_file_offset >= (uint64_t) st.st_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
key_file_size = st.st_size - key_file_offset;
}
STRV_FOREACH(i, search_path) {
_cleanup_free_ char *joined;
buffer = malloc(key_file_size);
if (!buffer)
return log_oom();
joined = path_join(*i, key_file);
if (!joined)
return log_oom();
if (key_file_offset > 0)
n = pread(fd, buffer, key_file_size, key_file_offset);
else
n = read(fd, buffer, key_file_size);
if (n < 0)
return log_error_errno(errno, "Failed to read key file '%s': %m", key_file);
if (n == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
r = read_full_file_full(
AT_FDCWD, joined, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
bindname,
(char**) ret_key, ret_key_size);
if (r >= 0)
return 1;
if (r != -ENOENT)
return log_error_errno(r, "Failed to load key file '%s': %m", key_file);
}
*ret_key = TAKE_PTR(buffer);
*ret_key_size = (size_t) n;
/* Search path supplied, but file not found, report by returning NULL, but not failing */
*ret_key = NULL;
*ret_key_size = 0;
return 0;
return 1;
}

View File

@ -4,9 +4,10 @@
#include <inttypes.h>
#include <sys/types.h>
int find_key_file(
int load_key_file(
const char *key_file,
char **search_path,
const char *bindname,
size_t key_file_size,
uint64_t key_file_offset,
void **ret_key,
size_t *ret_key_size);

View File

@ -10,14 +10,13 @@
#include "alloc-util.h"
#include "ask-password-api.h"
#include "cryptsetup-pkcs11.h"
#include "cryptsetup-keyfile.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-util.h"
#include "macro.h"
#include "memory-util.h"
#include "pkcs11-util.h"
#include "random-util.h"
#include "stat-util.h"
#include "strv.h"
@ -96,7 +95,6 @@ static int pkcs11_callback(
}
int decrypt_pkcs11_key(
const char *volume_name,
const char *friendly_name,
const char *pkcs11_uri,
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
@ -128,19 +126,7 @@ int decrypt_pkcs11_key(
data.free_encrypted_key = false;
} else {
_cleanup_free_ char *bindname = NULL;
/* If we read the key via AF_UNIX, make this client recognizable */
if (asprintf(&bindname, "@%" PRIx64"/cryptsetup-pkcs11/%s", random_u64(), volume_name) < 0)
return log_oom();
r = read_full_file_full(
AT_FDCWD, key_file,
key_file_offset == 0 ? UINT64_MAX : key_file_offset,
key_file_size == 0 ? SIZE_MAX : key_file_size,
READ_FULL_FILE_CONNECT_SOCKET,
bindname,
(char**) &data.encrypted_key, &data.encrypted_key_size);
r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
if (r < 0)
return r;

View File

@ -9,7 +9,6 @@
#if HAVE_P11KIT
int decrypt_pkcs11_key(
const char *volume_name,
const char *friendly_name,
const char *pkcs11_uri,
const char *key_file,
@ -24,7 +23,6 @@ int decrypt_pkcs11_key(
#else
static inline int decrypt_pkcs11_key(
const char *volume_name,
const char *friendly_name,
const char *pkcs11_uri,
const char *key_file,

View File

@ -29,7 +29,6 @@
#include "path-util.h"
#include "pkcs11-util.h"
#include "pretty-print.h"
#include "random-util.h"
#include "string-util.h"
#include "strv.h"
@ -551,15 +550,6 @@ static int attach_tcrypt(
return 0;
}
static char *make_bindname(const char *volume) {
char *s;
if (asprintf(&s, "@%" PRIx64"/cryptsetup/%s", random_u64(), volume) < 0)
return NULL;
return s;
}
static int attach_luks_or_plain_or_bitlk(
struct crypt_device *cd,
const char *name,
@ -646,7 +636,6 @@ static int attach_luks_or_plain_or_bitlk(
bool processed = false;
r = decrypt_pkcs11_key(
name,
friendly,
arg_pkcs11_uri,
key_file, arg_keyfile_size, arg_keyfile_offset,
@ -746,32 +735,15 @@ static int attach_luks_or_plain_or_bitlk(
return log_error_errno(r, "Failed to activate: %m");
} else if (key_file) {
_cleanup_(erase_and_freep) char *kfdata = NULL;
_cleanup_free_ char *bindname = NULL;
size_t kfsize;
/* If we read the key via AF_UNIX, make this client recognizable */
bindname = make_bindname(name);
if (!bindname)
return log_oom();
r = read_full_file_full(
AT_FDCWD, key_file,
arg_keyfile_offset == 0 ? UINT64_MAX : arg_keyfile_offset,
arg_keyfile_size == 0 ? SIZE_MAX : arg_keyfile_size,
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
bindname,
&kfdata, &kfsize);
if (r == -ENOENT) {
log_error_errno(r, "Failed to activate, key file '%s' missing.", key_file);
return -EAGAIN; /* Log actual error, but return EAGAIN */
}
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, kfdata, kfsize, flags);
r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
if (r == -EPERM) {
log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
return -EAGAIN; /* Log actual error, but return EAGAIN */
}
if (r == -EINVAL) {
log_error_errno(r, "Failed to activate with key file '%s'. (Key file missing?)", key_file);
return -EAGAIN; /* Log actual error, but return EAGAIN */
}
if (r < 0)
return log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
@ -908,22 +880,16 @@ static int run(int argc, char *argv[]) {
(void) mlockall(MCL_FUTURE);
if (!key_file) {
_cleanup_free_ char *bindname = NULL;
const char *fn;
bindname = make_bindname(argv[2]);
if (!bindname)
return log_oom();
/* If a key file is not explicitly specified, search for a key in a well defined
* search path, and load it. */
fn = strjoina(argv[2], ".key");
r = find_key_file(
fn,
STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
bindname,
&key_data, &key_data_size);
r = load_key_file(fn,
STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
0, 0, /* Note we leave arg_keyfile_offset/arg_keyfile_size as something that only applies to arg_keyfile! */
&key_data, &key_data_size);
if (r < 0)
return r;
if (r > 0)

View File

@ -22,7 +22,6 @@
#include "log.h"
#include "logs-show.h"
#include "main-func.h"
#include "memory-util.h"
#include "microhttpd-util.h"
#include "os-util.h"
#include "parse-util.h"
@ -38,7 +37,7 @@ static char *arg_cert_pem = NULL;
static char *arg_trust_pem = NULL;
static const char *arg_directory = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_key_pem, erase_and_freep);
STATIC_DESTRUCTOR_REGISTER(arg_key_pem, freep);
STATIC_DESTRUCTOR_REGISTER(arg_cert_pem, freep);
STATIC_DESTRUCTOR_REGISTER(arg_trust_pem, freep);
@ -897,11 +896,7 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_key_pem)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Key file specified twice");
r = read_full_file_full(
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&arg_key_pem, NULL);
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_key_pem, NULL);
if (r < 0)
return log_error_errno(r, "Failed to read key file: %m");
assert(arg_key_pem);
@ -911,11 +906,7 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_cert_pem)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Certificate file specified twice");
r = read_full_file_full(
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&arg_cert_pem, NULL);
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_cert_pem, NULL);
if (r < 0)
return log_error_errno(r, "Failed to read certificate file: %m");
assert(arg_cert_pem);
@ -926,18 +917,14 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_trust_pem)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"CA certificate file specified twice");
r = read_full_file_full(
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&arg_trust_pem, NULL);
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_trust_pem, NULL);
if (r < 0)
return log_error_errno(r, "Failed to read CA certificate file: %m");
assert(arg_trust_pem);
break;
#else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --trust= is not available.");
"Option --trust is not available.");
#endif
case 'D':
arg_directory = optarg;

View File

@ -13,7 +13,6 @@
#include "journal-remote-write.h"
#include "journal-remote.h"
#include "main-func.h"
#include "memory-util.h"
#include "pretty-print.h"
#include "process-util.h"
#include "rlimit-util.h"
@ -1078,20 +1077,12 @@ static int parse_argv(int argc, char *argv[]) {
static int load_certificates(char **key, char **cert, char **trust) {
int r;
r = read_full_file_full(
AT_FDCWD, arg_key ?: PRIV_KEY_FILE, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
NULL,
key, NULL);
r = read_full_file_full(AT_FDCWD, arg_key ?: PRIV_KEY_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, key, NULL);
if (r < 0)
return log_error_errno(r, "Failed to read key from file '%s': %m",
arg_key ?: PRIV_KEY_FILE);
r = read_full_file_full(
AT_FDCWD, arg_cert ?: CERT_FILE, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
cert, NULL);
r = read_full_file_full(AT_FDCWD, arg_cert ?: CERT_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, cert, NULL);
if (r < 0)
return log_error_errno(r, "Failed to read certificate from file '%s': %m",
arg_cert ?: CERT_FILE);
@ -1099,11 +1090,7 @@ static int load_certificates(char **key, char **cert, char **trust) {
if (arg_trust_all)
log_info("Certificate checking disabled.");
else {
r = read_full_file_full(
AT_FDCWD, arg_trust ?: TRUST_FILE, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
trust, NULL);
r = read_full_file_full(AT_FDCWD, arg_trust ?: TRUST_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, trust, NULL);
if (r < 0)
return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
arg_trust ?: TRUST_FILE);
@ -1119,8 +1106,7 @@ static int load_certificates(char **key, char **cert, char **trust) {
static int run(int argc, char **argv) {
_cleanup_(journal_remote_server_destroy) RemoteServer s = {};
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_cleanup_(erase_and_freep) char *key = NULL;
_cleanup_free_ char *cert = NULL, *trust = NULL;
_cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
int r;
log_show_color(true);

View File

@ -38,9 +38,6 @@
#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
#define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report
* transient failure. */
typedef struct sd_dhcp_client_id {
uint8_t type;
union {
@ -1190,7 +1187,7 @@ static int client_timeout_resend(
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
usec_t next_timeout;
usec_t next_timeout = 0;
uint64_t time_now;
uint32_t time_left;
int r;
@ -1206,14 +1203,17 @@ static int client_timeout_resend(
switch (client->state) {
case DHCP_STATE_RENEWING:
time_left = (client->lease->t2 - client->lease->t1) / 2;
if (time_left < 60)
time_left = 60;
next_timeout = time_now + time_left * USEC_PER_SEC;
break;
case DHCP_STATE_REBINDING:
time_left = (client->lease->lifetime - client->lease->t2) / 2;
if (time_left < 60)
time_left = 60;
@ -1230,20 +1230,24 @@ static int client_timeout_resend(
r = client_start(client);
if (r < 0)
goto error;
log_dhcp_client(client, "REBOOTED");
return 0;
else {
log_dhcp_client(client, "REBOOTED");
return 0;
}
case DHCP_STATE_INIT:
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_SELECTING:
case DHCP_STATE_REQUESTING:
case DHCP_STATE_BOUND:
if (client->attempt >= client->max_attempts)
if (client->attempt < client->max_attempts)
client->attempt++;
else
goto error;
client->attempt++;
next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
break;
case DHCP_STATE_STOPPED:
@ -1291,10 +1295,12 @@ static int client_timeout_resend(
client->state = DHCP_STATE_REBOOTING;
client->request_sent = time_now;
break;
case DHCP_STATE_REBOOTING:
case DHCP_STATE_BOUND:
break;
case DHCP_STATE_STOPPED:
@ -1302,9 +1308,6 @@ static int client_timeout_resend(
goto error;
}
if (client->attempt >= TRANSIENT_FAILURE_ATTEMPTS)
client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE);
return 0;
error:

View File

@ -736,10 +736,3 @@ global:
sd_device_has_current_tag;
sd_device_set_sysattr_valuef;
} LIBSYSTEMD_246;
LIBSYSTEMD_248 {
global:
sd_event_source_set_ratelimit;
sd_event_source_get_ratelimit;
sd_event_source_is_ratelimited;
} LIBSYSTEMD_246;

View File

@ -11,7 +11,6 @@
#include "hashmap.h"
#include "list.h"
#include "prioq.h"
#include "ratelimit.h"
typedef enum EventSourceType {
SOURCE_IO,
@ -62,7 +61,6 @@ struct sd_event_source {
bool dispatching:1;
bool floating:1;
bool exit_on_failure:1;
bool ratelimited:1;
int64_t priority;
unsigned pending_index;
@ -74,13 +72,6 @@ struct sd_event_source {
LIST_FIELDS(sd_event_source, sources);
RateLimit rate_limit;
/* These are primarily fields relevant for time event sources, but since any event source can
* effectively become one when rate-limited, this is part of the common fields. */
unsigned earliest_index;
unsigned latest_index;
union {
struct {
sd_event_io_handler_t callback;
@ -93,6 +84,8 @@ struct sd_event_source {
struct {
sd_event_time_handler_t callback;
usec_t next, accuracy;
unsigned earliest_index;
unsigned latest_index;
} time;
struct {
sd_event_signal_handler_t callback;

View File

@ -37,16 +37,6 @@ static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) {
s->child.options == WEXITED;
}
static bool event_source_is_online(sd_event_source *s) {
assert(s);
return s->enabled != SD_EVENT_OFF && !s->ratelimited;
}
static bool event_source_is_offline(sd_event_source *s) {
assert(s);
return s->enabled == SD_EVENT_OFF || s->ratelimited;
}
static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
[SOURCE_IO] = "io",
[SOURCE_TIME_REALTIME] = "realtime",
@ -65,25 +55,7 @@ static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX]
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int);
#define EVENT_SOURCE_IS_TIME(t) \
IN_SET((t), \
SOURCE_TIME_REALTIME, \
SOURCE_TIME_BOOTTIME, \
SOURCE_TIME_MONOTONIC, \
SOURCE_TIME_REALTIME_ALARM, \
SOURCE_TIME_BOOTTIME_ALARM)
#define EVENT_SOURCE_CAN_RATE_LIMIT(t) \
IN_SET((t), \
SOURCE_IO, \
SOURCE_TIME_REALTIME, \
SOURCE_TIME_BOOTTIME, \
SOURCE_TIME_MONOTONIC, \
SOURCE_TIME_REALTIME_ALARM, \
SOURCE_TIME_BOOTTIME_ALARM, \
SOURCE_SIGNAL, \
SOURCE_DEFER, \
SOURCE_INOTIFY)
#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM)
struct sd_event {
unsigned n_ref;
@ -109,7 +81,7 @@ struct sd_event {
Hashmap *signal_data; /* indexed by priority */
Hashmap *child_sources;
unsigned n_online_child_sources;
unsigned n_enabled_child_sources;
Set *post_sources;
@ -148,7 +120,7 @@ struct sd_event {
LIST_HEAD(sd_event_source, sources);
usec_t last_run_usec, last_log_usec;
usec_t last_run, last_log;
unsigned delays[sizeof(usec_t) * 8];
};
@ -174,11 +146,6 @@ static int pending_prioq_compare(const void *a, const void *b) {
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
/* Non rate-limited ones first. */
r = CMP(!!x->ratelimited, !!y->ratelimited);
if (r != 0)
return r;
/* Lower priority values first */
r = CMP(x->priority, y->priority);
if (r != 0)
@ -201,11 +168,6 @@ static int prepare_prioq_compare(const void *a, const void *b) {
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
/* Non rate-limited ones first. */
r = CMP(!!x->ratelimited, !!y->ratelimited);
if (r != 0)
return r;
/* Move most recently prepared ones last, so that we can stop
* preparing as soon as we hit one that has already been
* prepared in the current iteration */
@ -217,30 +179,12 @@ static int prepare_prioq_compare(const void *a, const void *b) {
return CMP(x->priority, y->priority);
}
static usec_t time_event_source_next(const sd_event_source *s) {
assert(s);
/* We have two kinds of event sources that have elapsation times associated with them: the actual
* time based ones and the ones for which a ratelimit can be in effect (where we want to be notified
* once the ratelimit time window ends). Let's return the next elapsing time depending on what we are
* looking at here. */
if (s->ratelimited) { /* If rate-limited the next elapsation is when the ratelimit time window ends */
assert(s->rate_limit.begin != 0);
assert(s->rate_limit.interval != 0);
return usec_add(s->rate_limit.begin, s->rate_limit.interval);
}
/* Otherwise this must be a time event source, if not ratelimited */
if (EVENT_SOURCE_IS_TIME(s->type))
return s->time.next;
return USEC_INFINITY;
}
static int earliest_time_prioq_compare(const void *a, const void *b) {
const sd_event_source *x = a, *y = b;
assert(EVENT_SOURCE_IS_TIME(x->type));
assert(x->type == y->type);
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
return -1;
@ -254,30 +198,19 @@ static int earliest_time_prioq_compare(const void *a, const void *b) {
return 1;
/* Order by time */
return CMP(time_event_source_next(x), time_event_source_next(y));
return CMP(x->time.next, y->time.next);
}
static usec_t time_event_source_latest(const sd_event_source *s) {
assert(s);
if (s->ratelimited) { /* For ratelimited stuff the earliest and the latest time shall actually be the
* same, as we should avoid adding additional inaccuracy on an inaccuracy time
* window */
assert(s->rate_limit.begin != 0);
assert(s->rate_limit.interval != 0);
return usec_add(s->rate_limit.begin, s->rate_limit.interval);
}
/* Must be a time event source, if not ratelimited */
if (EVENT_SOURCE_IS_TIME(s->type))
return usec_add(s->time.next, s->time.accuracy);
return USEC_INFINITY;
return usec_add(s->time.next, s->time.accuracy);
}
static int latest_time_prioq_compare(const void *a, const void *b) {
const sd_event_source *x = a, *y = b;
assert(EVENT_SOURCE_IS_TIME(x->type));
assert(x->type == y->type);
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
return -1;
@ -447,7 +380,7 @@ static void source_io_unregister(sd_event_source *s) {
return;
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0)
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m",
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
strna(s->description), event_source_type_to_string(s->type));
s->io.registered = false;
@ -489,7 +422,7 @@ static void source_child_pidfd_unregister(sd_event_source *s) {
if (EVENT_SOURCE_WATCH_PIDFD(s))
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0)
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m",
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
strna(s->description), event_source_type_to_string(s->type));
s->child.registered = false;
@ -728,12 +661,12 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig)
* and possibly drop the signalfd for it. */
if (sig == SIGCHLD &&
e->n_online_child_sources > 0)
e->n_enabled_child_sources > 0)
return;
if (e->signal_sources &&
e->signal_sources[sig] &&
event_source_is_online(e->signal_sources[sig]))
e->signal_sources[sig]->enabled != SD_EVENT_OFF)
return;
/*
@ -780,32 +713,13 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) {
struct clock_data *d;
assert(s);
assert(EVENT_SOURCE_IS_TIME(s->type));
/* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy,
* pending, enable state. Makes sure the two prioq's are ordered properly again. */
if (s->ratelimited)
d = &s->event->monotonic;
else {
assert(EVENT_SOURCE_IS_TIME(s->type));
assert_se(d = event_get_clock_data(s->event, s->type));
}
prioq_reshuffle(d->earliest, s, &s->earliest_index);
prioq_reshuffle(d->latest, s, &s->latest_index);
d->needs_rearm = true;
}
static void event_source_time_prioq_remove(
sd_event_source *s,
struct clock_data *d) {
assert(s);
assert(d);
prioq_remove(d->earliest, s, &s->earliest_index);
prioq_remove(d->latest, s, &s->latest_index);
s->earliest_index = s->latest_index = PRIOQ_IDX_NULL;
assert_se(d = event_get_clock_data(s->event, s->type));
prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
prioq_reshuffle(d->latest, s, &s->time.latest_index);
d->needs_rearm = true;
}
@ -831,18 +745,17 @@ static void source_disconnect(sd_event_source *s) {
case SOURCE_TIME_BOOTTIME:
case SOURCE_TIME_MONOTONIC:
case SOURCE_TIME_REALTIME_ALARM:
case SOURCE_TIME_BOOTTIME_ALARM:
/* Only remove this event source from the time event source here if it is not ratelimited. If
* it is ratelimited, we'll remove it below, separately. Why? Because the clock used might
* differ: ratelimiting always uses CLOCK_MONOTONIC, but timer events might use any clock */
case SOURCE_TIME_BOOTTIME_ALARM: {
struct clock_data *d;
if (!s->ratelimited) {
struct clock_data *d;
assert_se(d = event_get_clock_data(s->event, s->type));
event_source_time_prioq_remove(s, d);
}
d = event_get_clock_data(s->event, s->type);
assert(d);
prioq_remove(d->earliest, s, &s->time.earliest_index);
prioq_remove(d->latest, s, &s->time.latest_index);
d->needs_rearm = true;
break;
}
case SOURCE_SIGNAL:
if (s->signal.sig > 0) {
@ -857,9 +770,9 @@ static void source_disconnect(sd_event_source *s) {
case SOURCE_CHILD:
if (s->child.pid > 0) {
if (event_source_is_online(s)) {
assert(s->event->n_online_child_sources > 0);
s->event->n_online_child_sources--;
if (s->enabled != SD_EVENT_OFF) {
assert(s->event->n_enabled_child_sources > 0);
s->event->n_enabled_child_sources--;
}
(void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid));
@ -929,9 +842,6 @@ static void source_disconnect(sd_event_source *s) {
if (s->prepare)
prioq_remove(s->event->prepare, s, &s->prepare_index);
if (s->ratelimited)
event_source_time_prioq_remove(s, &s->event->monotonic);
event = TAKE_PTR(s->event);
LIST_REMOVE(sources, event->sources, s);
event->n_sources--;
@ -1178,52 +1088,6 @@ static int time_exit_callback(sd_event_source *s, uint64_t usec, void *userdata)
return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
}
static int setup_clock_data(sd_event *e, struct clock_data *d, clockid_t clock) {
int r;
assert(d);
if (d->fd < 0) {
r = event_setup_timer_fd(e, d, clock);
if (r < 0)
return r;
}
r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare);
if (r < 0)
return r;
r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare);
if (r < 0)
return r;
return 0;
}
static int event_source_time_prioq_put(
sd_event_source *s,
struct clock_data *d) {
int r;
assert(s);
assert(d);
r = prioq_put(d->earliest, s, &s->earliest_index);
if (r < 0)
return r;
r = prioq_put(d->latest, s, &s->latest_index);
if (r < 0) {
assert_se(prioq_remove(d->earliest, s, &s->earliest_index) > 0);
s->earliest_index = PRIOQ_IDX_NULL;
return r;
}
d->needs_rearm = true;
return 0;
}
_public_ int sd_event_add_time(
sd_event *e,
sd_event_source **ret,
@ -1254,12 +1118,23 @@ _public_ int sd_event_add_time(
if (!callback)
callback = time_exit_callback;
assert_se(d = event_get_clock_data(e, type));
d = event_get_clock_data(e, type);
assert(d);
r = setup_clock_data(e, d, clock);
r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare);
if (r < 0)
return r;
r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare);
if (r < 0)
return r;
if (d->fd < 0) {
r = event_setup_timer_fd(e, d, clock);
if (r < 0)
return r;
}
s = source_new(e, !ret, type);
if (!s)
return -ENOMEM;
@ -1267,11 +1142,17 @@ _public_ int sd_event_add_time(
s->time.next = usec;
s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy;
s->time.callback = callback;
s->earliest_index = s->latest_index = PRIOQ_IDX_NULL;
s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL;
s->userdata = userdata;
s->enabled = SD_EVENT_ONESHOT;
r = event_source_time_prioq_put(s, d);
d->needs_rearm = true;
r = prioq_put(d->earliest, s, &s->time.earliest_index);
if (r < 0)
return r;
r = prioq_put(d->latest, s, &s->time.latest_index);
if (r < 0)
return r;
@ -1404,7 +1285,7 @@ _public_ int sd_event_add_child(
if (!callback)
callback = child_exit_callback;
if (e->n_online_child_sources == 0) {
if (e->n_enabled_child_sources == 0) {
/* Caller must block SIGCHLD before using us to watch children, even if pidfd is available,
* for compatibility with pre-pidfd and because we don't want the reap the child processes
* ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to
@ -1469,7 +1350,7 @@ _public_ int sd_event_add_child(
e->need_process_child = true;
}
e->n_online_child_sources++;
e->n_enabled_child_sources++;
if (ret)
*ret = s;
@ -1501,7 +1382,7 @@ _public_ int sd_event_add_child_pidfd(
if (!callback)
callback = child_exit_callback;
if (e->n_online_child_sources == 0) {
if (e->n_enabled_child_sources == 0) {
r = signal_is_blocked(SIGCHLD);
if (r < 0)
return r;
@ -1551,7 +1432,7 @@ _public_ int sd_event_add_child_pidfd(
e->need_process_child = true;
}
e->n_online_child_sources++;
e->n_enabled_child_sources++;
if (ret)
*ret = s;
@ -2137,7 +2018,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
if (s->io.fd == fd)
return 0;
if (event_source_is_offline(s)) {
if (s->enabled == SD_EVENT_OFF) {
s->io.fd = fd;
s->io.registered = false;
} else {
@ -2204,7 +2085,7 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events)
if (r < 0)
return r;
if (event_source_is_online(s)) {
if (s->enabled != SD_EVENT_OFF) {
r = source_io_register(s, s->enabled, events);
if (r < 0)
return r;
@ -2307,7 +2188,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority)
event_gc_inode_data(s->event, old_inode_data);
} else if (s->type == SOURCE_SIGNAL && event_source_is_online(s)) {
} else if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) {
struct signal_data *old, *d;
/* Move us from the signalfd belonging to the old
@ -2344,39 +2225,29 @@ fail:
return r;
}
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) {
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
assert_return(s, -EINVAL);
assert_return(!event_pid_changed(s->event), -ECHILD);
if (ret)
*ret = s->enabled;
if (m)
*m = s->enabled;
return s->enabled != SD_EVENT_OFF;
}
static int event_source_offline(
sd_event_source *s,
int enabled,
bool ratelimited) {
bool was_offline;
static int event_source_disable(sd_event_source *s) {
int r;
assert(s);
assert(enabled == SD_EVENT_OFF || ratelimited);
assert(s->enabled != SD_EVENT_OFF);
/* Unset the pending flag when this event source is disabled */
if (s->enabled != SD_EVENT_OFF &&
enabled == SD_EVENT_OFF &&
!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
r = source_set_pending(s, false);
if (r < 0)
return r;
}
was_offline = event_source_is_offline(s);
s->enabled = enabled;
s->ratelimited = ratelimited;
s->enabled = SD_EVENT_OFF;
switch (s->type) {
@ -2397,10 +2268,8 @@ static int event_source_offline(
break;
case SOURCE_CHILD:
if (!was_offline) {
assert(s->event->n_online_child_sources > 0);
s->event->n_online_child_sources--;
}
assert(s->event->n_enabled_child_sources > 0);
s->event->n_enabled_child_sources--;
if (EVENT_SOURCE_WATCH_PIDFD(s))
source_child_pidfd_unregister(s);
@ -2421,42 +2290,26 @@ static int event_source_offline(
assert_not_reached("Wut? I shouldn't exist.");
}
return 1;
return 0;
}
static int event_source_online(
sd_event_source *s,
int enabled,
bool ratelimited) {
bool was_online;
static int event_source_enable(sd_event_source *s, int enable) {
int r;
assert(s);
assert(enabled != SD_EVENT_OFF || !ratelimited);
assert(IN_SET(enable, SD_EVENT_ON, SD_EVENT_ONESHOT));
assert(s->enabled == SD_EVENT_OFF);
/* Unset the pending flag when this event source is enabled */
if (s->enabled == SD_EVENT_OFF &&
enabled != SD_EVENT_OFF &&
!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
r = source_set_pending(s, false);
if (r < 0)
return r;
}
/* Are we really ready for onlining? */
if (enabled == SD_EVENT_OFF || ratelimited) {
/* Nope, we are not ready for onlining, then just update the precise state and exit */
s->enabled = enabled;
s->ratelimited = ratelimited;
return 0;
}
was_online = event_source_is_online(s);
switch (s->type) {
case SOURCE_IO:
r = source_io_register(s, enabled, s->io.events);
r = source_io_register(s, enable, s->io.events);
if (r < 0)
return r;
break;
@ -2474,7 +2327,7 @@ static int event_source_online(
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
/* yes, we have pidfd */
r = source_child_pidfd_register(s, enabled);
r = source_child_pidfd_register(s, enable);
if (r < 0)
return r;
} else {
@ -2487,8 +2340,8 @@ static int event_source_online(
}
}
if (!was_online)
s->event->n_online_child_sources++;
s->event->n_enabled_child_sources++;
break;
case SOURCE_TIME_REALTIME:
@ -2506,8 +2359,7 @@ static int event_source_online(
assert_not_reached("Wut? I shouldn't exist.");
}
s->enabled = enabled;
s->ratelimited = ratelimited;
s->enabled = enable;
/* Non-failing operations below */
switch (s->type) {
@ -2527,7 +2379,7 @@ static int event_source_online(
break;
}
return 1;
return 0;
}
_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
@ -2545,7 +2397,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
return 0;
if (m == SD_EVENT_OFF)
r = event_source_offline(s, m, s->ratelimited);
r = event_source_disable(s);
else {
if (s->enabled != SD_EVENT_OFF) {
/* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the
@ -2554,7 +2406,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
return 0;
}
r = event_source_online(s, m, s->ratelimited);
r = event_source_enable(s, m);
}
if (r < 0)
return r;
@ -2811,96 +2663,6 @@ _public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata)
return ret;
}
static int event_source_enter_ratelimited(sd_event_source *s) {
int r;
assert(s);
/* When an event source becomes ratelimited, we place it in the CLOCK_MONOTONIC priority queue, with
* the end of the rate limit time window, much as if it was a timer event source. */
if (s->ratelimited)
return 0; /* Already ratelimited, this is a NOP hence */
/* Make sure we can install a CLOCK_MONOTONIC event further down. */
r = setup_clock_data(s->event, &s->event->monotonic, CLOCK_MONOTONIC);
if (r < 0)
return r;
/* Timer event sources are already using the earliest/latest queues for the timer scheduling. Let's
* first remove them from the prioq appropriate for their own clock, so that we can use the prioq
* fields of the event source then for adding it to the CLOCK_MONOTONIC prioq instead. */
if (EVENT_SOURCE_IS_TIME(s->type))
event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type));
/* Now, let's add the event source to the monotonic clock instead */
r = event_source_time_prioq_put(s, &s->event->monotonic);
if (r < 0)
goto fail;
/* And let's take the event source officially offline */
r = event_source_offline(s, s->enabled, /* ratelimited= */ true);
if (r < 0) {
event_source_time_prioq_remove(s, &s->event->monotonic);
goto fail;
}
event_source_pp_prioq_reshuffle(s);
log_debug("Event source %p (%s) entered rate limit state.", s, strna(s->description));
return 0;
fail:
/* Reinstall time event sources in the priority queue as before. This shouldn't fail, since the queue
* space for it should already be allocated. */
if (EVENT_SOURCE_IS_TIME(s->type))
assert_se(event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)) >= 0);
return r;
}
static int event_source_leave_ratelimit(sd_event_source *s) {
int r;
assert(s);
if (!s->ratelimited)
return 0;
/* Let's take the event source out of the monotonic prioq first. */
event_source_time_prioq_remove(s, &s->event->monotonic);
/* Let's then add the event source to its native clock prioq again — if this is a timer event source */
if (EVENT_SOURCE_IS_TIME(s->type)) {
r = event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type));
if (r < 0)
goto fail;
}
/* Let's try to take it online again. */
r = event_source_online(s, s->enabled, /* ratelimited= */ false);
if (r < 0) {
/* Do something roughly sensible when this failed: undo the two prioq ops above */
if (EVENT_SOURCE_IS_TIME(s->type))
event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type));
goto fail;
}
event_source_pp_prioq_reshuffle(s);
ratelimit_reset(&s->rate_limit);
log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description));
return 0;
fail:
/* Do something somewhat reasonable when we cannot move an event sources out of ratelimited mode:
* simply put it back in it, maybe we can then process it more successfully next iteration. */
assert_se(event_source_time_prioq_put(s, &s->event->monotonic) >= 0);
return r;
}
static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) {
usec_t c;
assert(e);
@ -2998,7 +2760,7 @@ static int event_arm_timer(
d->needs_rearm = false;
a = prioq_peek(d->earliest);
if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) {
if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) {
if (d->fd < 0)
return 0;
@ -3017,7 +2779,7 @@ static int event_arm_timer(
b = prioq_peek(d->latest);
assert_se(b && b->enabled != SD_EVENT_OFF);
t = sleep_between(e, time_event_source_next(a), time_event_source_latest(b));
t = sleep_between(e, a->time.next, time_event_source_latest(b));
if (d->next == t)
return 0;
@ -3095,22 +2857,10 @@ static int process_timer(
for (;;) {
s = prioq_peek(d->earliest);
if (!s || time_event_source_next(s) > n)
break;
if (s->ratelimited) {
/* This is an event sources whose ratelimit window has ended. Let's turn it on
* again. */
assert(s->ratelimited);
r = event_source_leave_ratelimit(s);
if (r < 0)
return r;
continue;
}
if (s->enabled == SD_EVENT_OFF || s->pending)
if (!s ||
s->time.next > n ||
s->enabled == SD_EVENT_OFF ||
s->pending)
break;
r = source_set_pending(s, true);
@ -3155,7 +2905,7 @@ static int process_child(sd_event *e) {
if (s->pending)
continue;
if (event_source_is_offline(s))
if (s->enabled == SD_EVENT_OFF)
continue;
if (s->child.exited)
@ -3202,7 +2952,7 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
if (s->pending)
return 0;
if (event_source_is_offline(s))
if (s->enabled == SD_EVENT_OFF)
return 0;
if (!EVENT_SOURCE_WATCH_PIDFD(s))
@ -3362,7 +3112,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) {
LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) {
if (event_source_is_offline(s))
if (s->enabled == SD_EVENT_OFF)
continue;
r = source_set_pending(s, true);
@ -3398,7 +3148,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) {
* sources if IN_IGNORED or IN_UNMOUNT is set. */
LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) {
if (event_source_is_offline(s))
if (s->enabled == SD_EVENT_OFF)
continue;
if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 &&
@ -3452,16 +3202,6 @@ static int source_dispatch(sd_event_source *s) {
* callback might have invalidated/disconnected the event source. */
saved_event = sd_event_ref(s->event);
/* Check if we hit the ratelimit for this event source, if so, let's disable it. */
assert(!s->ratelimited);
if (!ratelimit_below(&s->rate_limit)) {
r = event_source_enter_ratelimited(s);
if (r < 0)
return r;
return 1;
}
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
r = source_set_pending(s, false);
if (r < 0)
@ -3475,7 +3215,7 @@ static int source_dispatch(sd_event_source *s) {
* post sources as pending */
SET_FOREACH(z, s->event->post_sources) {
if (event_source_is_offline(z))
if (z->enabled == SD_EVENT_OFF)
continue;
r = source_set_pending(z, true);
@ -3595,7 +3335,7 @@ static int event_prepare(sd_event *e) {
sd_event_source *s;
s = prioq_peek(e->prepare);
if (!s || s->prepare_iteration == e->iteration || event_source_is_offline(s))
if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF)
break;
s->prepare_iteration = e->iteration;
@ -3630,17 +3370,18 @@ static int event_prepare(sd_event *e) {
static int dispatch_exit(sd_event *e) {
sd_event_source *p;
_cleanup_(sd_event_unrefp) sd_event *ref = NULL;
int r;
assert(e);
p = prioq_peek(e->exit);
if (!p || event_source_is_offline(p)) {
if (!p || p->enabled == SD_EVENT_OFF) {
e->state = SD_EVENT_FINISHED;
return 0;
}
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
ref = sd_event_ref(e);
e->iteration++;
e->state = SD_EVENT_EXITING;
r = source_dispatch(p);
@ -3657,7 +3398,7 @@ static sd_event_source* event_next_pending(sd_event *e) {
if (!p)
return NULL;
if (event_source_is_offline(p))
if (p->enabled == SD_EVENT_OFF)
return NULL;
return p;
@ -3736,9 +3477,6 @@ _public_ int sd_event_prepare(sd_event *e) {
* syscalls */
assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO);
/* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
if (e->exit_requested)
goto pending;
@ -3944,8 +3682,9 @@ _public_ int sd_event_dispatch(sd_event *e) {
p = event_next_pending(e);
if (p) {
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
_cleanup_(sd_event_unrefp) sd_event *ref = NULL;
ref = sd_event_ref(e);
e->state = SD_EVENT_RUNNING;
r = source_dispatch(p);
e->state = SD_EVENT_INITIAL;
@ -3979,32 +3718,29 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
if (e->profile_delays && e->last_run_usec != 0) {
if (e->profile_delays && e->last_run) {
usec_t this_run;
unsigned l;
this_run = now(CLOCK_MONOTONIC);
l = u64log2(this_run - e->last_run_usec);
l = u64log2(this_run - e->last_run);
assert(l < ELEMENTSOF(e->delays));
e->delays[l]++;
if (this_run - e->last_log_usec >= 5*USEC_PER_SEC) {
if (this_run - e->last_log >= 5*USEC_PER_SEC) {
event_log_delays(e);
e->last_log_usec = this_run;
e->last_log = this_run;
}
}
/* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
r = sd_event_prepare(e);
if (r == 0)
/* There was nothing? Then wait... */
r = sd_event_wait(e, timeout);
if (e->profile_delays)
e->last_run_usec = now(CLOCK_MONOTONIC);
e->last_run = now(CLOCK_MONOTONIC);
if (r > 0) {
/* There's something now, then let's dispatch it */
@ -4019,6 +3755,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
}
_public_ int sd_event_loop(sd_event *e) {
_cleanup_(sd_event_unrefp) sd_event *ref = NULL;
int r;
assert_return(e, -EINVAL);
@ -4026,7 +3763,7 @@ _public_ int sd_event_loop(sd_event *e) {
assert_return(!event_pid_changed(e), -ECHILD);
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
ref = sd_event_ref(e);
while (e->state != SD_EVENT_FINISHED) {
r = sd_event_run(e, (uint64_t) -1);
@ -4271,53 +4008,3 @@ _public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) {
s->exit_on_failure = b;
return 1;
}
_public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval, unsigned burst) {
int r;
assert_return(s, -EINVAL);
/* Turning on ratelimiting on event source types that don't support it, is a loggable offense. Doing
* so is a programming error. */
assert_return(EVENT_SOURCE_CAN_RATE_LIMIT(s->type), -EDOM);
/* When ratelimiting is configured we'll always reset the rate limit state first and start fresh,
* non-ratelimited. */
r = event_source_leave_ratelimit(s);
if (r < 0)
return r;
s->rate_limit = (RateLimit) { interval, burst };
return 0;
}
_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) {
assert_return(s, -EINVAL);
/* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence
* don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */
if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type))
return -EDOM;
if (!ratelimit_configured(&s->rate_limit))
return -ENOEXEC;
if (ret_interval)
*ret_interval = s->rate_limit.interval;
if (ret_burst)
*ret_burst = s->rate_limit.burst;
return 0;
}
_public_ int sd_event_source_is_ratelimited(sd_event_source *s) {
assert_return(s, -EINVAL);
if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type))
return false;
if (!ratelimit_configured(&s->rate_limit))
return false;
return s->ratelimited;
}

View File

@ -589,100 +589,8 @@ static void test_pidfd(void) {
sd_event_unref(e);
}
static int ratelimit_io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
unsigned *c = (unsigned*) userdata;
*c += 1;
return 0;
}
static int ratelimit_time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
int r;
r = sd_event_source_set_enabled(s, SD_EVENT_ON);
if (r < 0)
log_warning_errno(r, "Failed to turn on notify event source: %m");
r = sd_event_source_set_time(s, usec + 1000);
if (r < 0)
log_error_errno(r, "Failed to restart watchdog event source: %m");
unsigned *c = (unsigned*) userdata;
*c += 1;
return 0;
}
static void test_ratelimit(void) {
_cleanup_close_pair_ int p[2] = {-1, -1};
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
uint64_t interval;
unsigned count, burst;
assert_se(sd_event_default(&e) >= 0);
assert_se(pipe2(p, O_CLOEXEC|O_NONBLOCK) >= 0);
assert_se(sd_event_add_io(e, &s, p[0], EPOLLIN, ratelimit_io_handler, &count) >= 0);
assert_se(sd_event_source_set_description(s, "test-ratelimit-io") >= 0);
assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 5) >= 0);
assert_se(sd_event_source_get_ratelimit(s, &interval, &burst) >= 0);
assert_se(interval == 1 * USEC_PER_SEC && burst == 5);
assert_se(write(p[1], "1", 1) == 1);
count = 0;
for (unsigned i = 0; i < 10; i++) {
log_debug("slow loop iteration %u", i);
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
assert_se(usleep(250 * USEC_PER_MSEC) >= 0);
}
assert_se(sd_event_source_is_ratelimited(s) == 0);
assert_se(count == 10);
log_info("ratelimit_io_handler: called %d times, event source not ratelimited", count);
assert_se(sd_event_source_set_ratelimit(s, 0, 0) >= 0);
assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 5) >= 0);
count = 0;
for (unsigned i = 0; i < 10; i++) {
log_debug("fast event loop iteration %u", i);
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
assert_se(usleep(10) >= 0);
}
log_info("ratelimit_io_handler: called %d times, event source got ratelimited", count);
assert_se(count < 10);
s = sd_event_source_unref(s);
safe_close_pair(p);
count = 0;
assert_se(sd_event_add_time_relative(e, &s, CLOCK_MONOTONIC, 1000, 1, ratelimit_time_handler, &count) >= 0);
assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) == 0);
do {
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
} while (!sd_event_source_is_ratelimited(s));
log_info("ratelimit_time_handler: called %d times, event source got ratelimited", count);
assert_se(count == 10);
/* In order to get rid of active rate limit client needs to disable it explicitely */
assert_se(sd_event_source_set_ratelimit(s, 0, 0) >= 0);
assert_se(!sd_event_source_is_ratelimited(s));
assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) >= 0);
do {
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
} while (!sd_event_source_is_ratelimited(s));
log_info("ratelimit_time_handler: called 10 more times, event source got ratelimited");
assert_se(count == 20);
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_setup_logging(LOG_INFO);
test_basic(true); /* test with pidfd */
test_basic(false); /* test without pidfd */
@ -695,7 +603,5 @@ int main(int argc, char *argv[]) {
test_pidfd();
test_ratelimit();
return 0;
}

View File

@ -986,7 +986,7 @@ static int macsec_read_key_file(NetDev *netdev, SecurityAssociation *sa) {
(void) warn_file_is_world_accessible(sa->key_file, NULL, NULL, 0);
r = read_full_file_full(
AT_FDCWD, sa->key_file, UINT64_MAX, SIZE_MAX,
AT_FDCWD, sa->key_file,
READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
NULL, (char **) &key, &key_len);
if (r < 0)

View File

@ -869,7 +869,7 @@ static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_
(void) warn_file_is_world_accessible(filename, NULL, NULL, 0);
r = read_full_file_full(
AT_FDCWD, filename, UINT64_MAX, SIZE_MAX,
AT_FDCWD, filename,
READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
NULL, &key, &key_len);
if (r < 0)

View File

@ -62,9 +62,11 @@ static struct DUID fallback_duid = { .type = DUID_TYPE_EN };
DUID* link_get_duid(Link *link) {
if (link->network->duid.type != _DUID_TYPE_INVALID)
return &link->network->duid;
else if (link->hw_addr.length == 0 && IN_SET(link->manager->duid.type, DUID_TYPE_LLT, DUID_TYPE_LL))
/* Fallback to DUID that works without MAC address.
* This is useful for tunnel devices without MAC address. */
else if (link->hw_addr.length == 0 &&
(link->manager->duid.type == DUID_TYPE_LLT ||
link->manager->duid.type == DUID_TYPE_LL))
/* Fallback to DUID that works without mac addresses.
* This is useful for tunnel devices without mac address. */
return &fallback_duid;
else
return &link->manager->duid;

View File

@ -70,10 +70,6 @@ static void dhcp4_check_ready(Link *link) {
return;
}
r = sd_ipv4ll_stop(link->ipv4ll);
if (r < 0)
log_link_warning_errno(link, r, "Failed to drop IPv4 link-local address, ignoring: %m");
link_check_ready(link);
}
@ -1052,7 +1048,10 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
switch (event) {
case SD_DHCP_CLIENT_EVENT_STOP:
if (link->ipv4ll) {
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4)) {
assert(link->ipv4ll);
log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address");
r = sd_ipv4ll_start(link->ipv4ll);
@ -1137,17 +1136,6 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
return -ENOMSG;
}
break;
case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE:
if (link->ipv4ll && !sd_ipv4ll_is_running(link->ipv4ll)) {
log_link_debug(link, "Problems acquiring DHCP lease, acquiring IPv4 link-local address");
r = sd_ipv4ll_start(link->ipv4ll);
if (r < 0)
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
}
break;
default:
if (event < 0)
log_link_warning_errno(link, event, "DHCP error: Client failed: %m");

View File

@ -148,7 +148,7 @@ int ipv4ll_configure(Link *link) {
assert(link);
if (!link_ipv4ll_enabled(link))
if (!link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4))
return 0;
if (!link->ipv4ll) {

View File

@ -55,8 +55,9 @@
#include "util.h"
#include "vrf.h"
bool link_ipv4ll_enabled(Link *link) {
bool link_ipv4ll_enabled(Link *link, AddressFamily mask) {
assert(link);
assert((mask & ~(ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) == 0);
if (link->flags & IFF_LOOPBACK)
return false;
@ -79,7 +80,7 @@ bool link_ipv4ll_enabled(Link *link) {
if (link->network->bond)
return false;
return link->network->link_local & ADDRESS_FAMILY_IPV4;
return link->network->link_local & mask;
}
bool link_ipv6ll_enabled(Link *link) {
@ -733,51 +734,77 @@ void link_check_ready(Link *link) {
if (link->state == LINK_STATE_CONFIGURED)
return;
if (link->state != LINK_STATE_CONFIGURING)
return (void) log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
if (link->state != LINK_STATE_CONFIGURING) {
log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state));
return;
}
if (!link->network)
return;
if (!link->addresses_configured)
return (void) log_link_debug(link, "%s(): static addresses are not configured.", __func__);
if (!link->addresses_configured) {
log_link_debug(link, "%s(): static addresses are not configured.", __func__);
return;
}
if (!link->neighbors_configured)
return (void) log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
if (!link->neighbors_configured) {
log_link_debug(link, "%s(): static neighbors are not configured.", __func__);
return;
}
SET_FOREACH(a, link->addresses)
if (!address_is_ready(a)) {
_cleanup_free_ char *str = NULL;
(void) in_addr_to_string(a->family, &a->in_addr, &str);
return (void) log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen);
log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen);
return;
}
if (!link->static_routes_configured)
return (void) log_link_debug(link, "%s(): static routes are not configured.", __func__);
if (!link->static_routes_configured) {
log_link_debug(link, "%s(): static routes are not configured.", __func__);
return;
}
if (!link->static_nexthops_configured)
return (void) log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
if (!link->static_nexthops_configured) {
log_link_debug(link, "%s(): static nexthops are not configured.", __func__);
return;
}
if (!link->routing_policy_rules_configured)
return (void) log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
if (!link->routing_policy_rules_configured) {
log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__);
return;
}
if (!link->tc_configured)
return (void) log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
if (!link->tc_configured) {
log_link_debug(link, "%s(): traffic controls are not configured.", __func__);
return;
}
if (!link->sr_iov_configured)
return (void) log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
if (!link->sr_iov_configured) {
log_link_debug(link, "%s(): SR-IOV is not configured.", __func__);
return;
}
if (!link->bridge_mdb_configured)
return (void) log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__);
if (!link->bridge_mdb_configured) {
log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__);
return;
}
if (link_has_carrier(link) || !link->network->configure_without_carrier) {
bool has_ndisc_address = false;
NDiscAddress *n;
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address_configured) {
log_link_debug(link, "%s(): IPv4LL is not configured.", __func__);
return;
}
if (link_ipv6ll_enabled(link) &&
in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address))
return (void) log_link_debug(link, "%s(): IPv6LL is not configured.", __func__);
in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) {
log_link_debug(link, "%s(): IPv6LL is not configured.", __func__);
return;
}
SET_FOREACH(n, link->ndisc_addresses)
if (!n->marked) {
@ -785,26 +812,28 @@ void link_check_ready(Link *link) {
break;
}
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_ipv4ll_enabled(link)) &&
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) &&
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
!link->ipv4ll_address_configured)
/* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
return (void) log_link_debug(link, "%s(): DHCP4, DHCP6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no dynamic address is assigned yet.", __func__);
return;
}
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
link_ipv6_accept_ra_enabled(link) || link_ipv4ll_enabled(link)) {
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) || link_ipv6_accept_ra_enabled(link)) {
if (!link->dhcp4_configured &&
!(link->dhcp6_address_configured && link->dhcp6_route_configured) &&
!(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) &&
!(link->ndisc_addresses_configured && link->ndisc_routes_configured) &&
!link->ipv4ll_address_configured)
/* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */
return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
/* When DHCP or RA is enabled, at least one protocol must provide an address, or
* an IPv4ll fallback address must be configured. */
log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
return;
}
log_link_debug(link, "%s(): dhcp4:%s ipv4ll:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s",
log_link_debug(link, "%s(): dhcp4:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s",
__func__,
yes_no(link->dhcp4_configured),
yes_no(link->ipv4ll_address_configured),
yes_no(link->dhcp6_address_configured),
yes_no(link->dhcp6_route_configured),
yes_no(link->dhcp6_pd_address_configured),
@ -815,6 +844,8 @@ void link_check_ready(Link *link) {
}
link_enter_configured(link);
return;
}
static int link_set_static_configs(Link *link) {
@ -1199,19 +1230,22 @@ static int link_acquire_ipv4_conf(Link *link) {
assert(link->manager);
assert(link->manager->event);
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4)) {
assert(link->ipv4ll);
log_link_debug(link, "Acquiring IPv4 link-local address");
r = sd_ipv4ll_start(link->ipv4ll);
if (r < 0)
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
}
if (link->dhcp_client) {
log_link_debug(link, "Acquiring DHCPv4 lease");
r = sd_dhcp_client_start(link->dhcp_client);
if (r < 0)
return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
} else if (link->ipv4ll) {
log_link_debug(link, "Acquiring IPv4 link-local address");
r = sd_ipv4ll_start(link->ipv4ll);
if (r < 0)
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
}
return 0;

View File

@ -231,7 +231,7 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address);
int link_set_mtu(Link *link, uint32_t mtu);
bool link_ipv4ll_enabled(Link *link);
bool link_ipv4ll_enabled(Link *link, AddressFamily mask);
int link_stop_engines(Link *link, bool may_keep_dhcp);

View File

@ -210,6 +210,13 @@ int network_verify(Network *network) {
if (network->link_local < 0)
network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
!FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
"Disabling the fallback assignment.", network->filename);
SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
}
/* IPMasquerade=yes implies IPForward=yes */
if (network->ip_masquerade)
network->ip_forward |= ADDRESS_FAMILY_IPV4;

View File

@ -15,6 +15,15 @@ static const char* const address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_IPV6] = "ipv6",
};
static const char* const link_local_address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_NO] = "no",
[ADDRESS_FAMILY_YES] = "yes",
[ADDRESS_FAMILY_IPV4] = "ipv4",
[ADDRESS_FAMILY_IPV6] = "ipv6",
[ADDRESS_FAMILY_FALLBACK] = "fallback",
[ADDRESS_FAMILY_FALLBACK_IPV4] = "ipv4-fallback",
};
static const char* const routing_policy_rule_address_family_table[_ADDRESS_FAMILY_MAX] = {
[ADDRESS_FAMILY_YES] = "both",
[ADDRESS_FAMILY_IPV4] = "ipv4",
@ -38,15 +47,7 @@ static const char* const dhcp_lease_server_type_table[_SD_DHCP_LEASE_SERVER_TYPE
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(address_family, AddressFamily, ADDRESS_FAMILY_YES);
AddressFamily link_local_address_family_from_string(const char *s) {
if (streq_ptr(s, "fallback")) /* compat name */
return ADDRESS_FAMILY_YES;
if (streq_ptr(s, "fallback-ipv4")) /* compat name */
return ADDRESS_FAMILY_IPV4;
return address_family_from_string(s);
}
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(link_local_address_family, AddressFamily, ADDRESS_FAMILY_YES);
DEFINE_STRING_TABLE_LOOKUP(routing_policy_rule_address_family, AddressFamily);
DEFINE_STRING_TABLE_LOOKUP(duplicate_address_detection_address_family, AddressFamily);
DEFINE_CONFIG_PARSE_ENUM(config_parse_link_local_address_family, link_local_address_family,

View File

@ -16,6 +16,8 @@ typedef enum AddressFamily {
ADDRESS_FAMILY_IPV4 = 1 << 0,
ADDRESS_FAMILY_IPV6 = 1 << 1,
ADDRESS_FAMILY_YES = ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6,
ADDRESS_FAMILY_FALLBACK_IPV4 = 1 << 2,
ADDRESS_FAMILY_FALLBACK = ADDRESS_FAMILY_FALLBACK_IPV4 | ADDRESS_FAMILY_IPV6,
_ADDRESS_FAMILY_MAX,
_ADDRESS_FAMILY_INVALID = -1,
} AddressFamily;
@ -32,6 +34,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_address_family_with_kernel);
const char *address_family_to_string(AddressFamily b) _const_;
AddressFamily address_family_from_string(const char *s) _pure_;
const char *link_local_address_family_to_string(AddressFamily b) _const_;
AddressFamily link_local_address_family_from_string(const char *s) _pure_;
const char *routing_policy_rule_address_family_to_string(AddressFamily b) _const_;

View File

@ -1589,10 +1589,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_oom();
}
r = read_full_file_full(AT_FDCWD, j ?: p, UINT64_MAX, SIZE_MAX,
flags,
NULL,
&data, &size);
r = read_full_file_full(AT_FDCWD, j ?: p, flags, NULL, &data, &size);
if (r < 0)
return log_error_errno(r, "Failed to read credential '%s': %m", j ?: p);

View File

@ -3621,11 +3621,7 @@ static int parse_argv(int argc, char *argv[]) {
_cleanup_(erase_and_freep) char *k = NULL;
size_t n = 0;
r = read_full_file_full(
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&k, &n);
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_SECURE|READ_FULL_FILE_CONNECT_SOCKET, NULL, &k, &n);
if (r < 0)
return log_error_errno(r, "Failed to read key file '%s': %m", optarg);

View File

@ -2115,7 +2115,7 @@ int verity_settings_load(
if (verity->root_hash && !verity->root_hash_sig) {
if (root_hash_sig_path) {
r = read_full_file(root_hash_sig_path, (char**) &root_hash_sig, &root_hash_sig_size);
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
if (r < 0 && r != -ENOENT)
return r;
@ -2131,7 +2131,7 @@ int verity_settings_load(
if (!p)
return -ENOMEM;
r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size);
r = read_full_file_full(AT_FDCWD, p, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
if (r < 0 && r != -ENOENT)
return r;
if (r >= 0)
@ -2145,7 +2145,7 @@ int verity_settings_load(
if (!p)
return -ENOMEM;
r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size);
r = read_full_file_full(AT_FDCWD, p, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
if (r < 0 && r != -ENOENT)
return r;
if (r >= 0)

View File

@ -3195,7 +3195,7 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags fla
if (f)
r = read_full_stream(f, &text, NULL);
else if (path)
r = read_full_file_full(dir_fd, path, UINT64_MAX, SIZE_MAX, 0, NULL, &text, NULL);
r = read_full_file_full(dir_fd, path, 0, NULL, &text, NULL);
else
return -EINVAL;
if (r < 0)

View File

@ -40,8 +40,6 @@ enum {
SD_DHCP_CLIENT_EVENT_EXPIRED = 3,
SD_DHCP_CLIENT_EVENT_RENEW = 4,
SD_DHCP_CLIENT_EVENT_SELECTING = 5,
SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts.
* The client may want to start acquiring link-local addresses. */
};
enum {

View File

@ -162,9 +162,6 @@ int sd_event_source_get_floating(sd_event_source *s);
int sd_event_source_set_floating(sd_event_source *s, int b);
int sd_event_source_get_exit_on_failure(sd_event_source *s);
int sd_event_source_set_exit_on_failure(sd_event_source *s, int b);
int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst);
int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst);
int sd_event_source_is_ratelimited(sd_event_source *s);
/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);

View File

@ -911,8 +911,8 @@ static void test_read_full_file_socket(void) {
_exit(EXIT_SUCCESS);
}
assert_se(read_full_file_full(AT_FDCWD, j, UINT64_MAX, SIZE_MAX, 0, NULL, &data, &size) == -ENXIO);
assert_se(read_full_file_full(AT_FDCWD, j, UINT64_MAX, SIZE_MAX, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0);
assert_se(read_full_file_full(AT_FDCWD, j, 0, NULL, &data, &size) == -ENXIO);
assert_se(read_full_file_full(AT_FDCWD, j, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0);
assert_se(size == strlen(TEST_STR));
assert_se(streq(data, TEST_STR));
@ -920,50 +920,6 @@ static void test_read_full_file_socket(void) {
#undef TEST_STR
}
static void test_read_full_file_offset_size(void) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_(unlink_and_freep) char *fn = NULL;
_cleanup_free_ char *rbuf = NULL;
size_t rbuf_size;
uint8_t buf[4711];
random_bytes(buf, sizeof(buf));
assert_se(tempfn_random_child(NULL, NULL, &fn) >= 0);
assert_se(f = fopen(fn, "we"));
assert_se(fwrite(buf, 1, sizeof(buf), f) == sizeof(buf));
assert_se(fflush_and_check(f) >= 0);
assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, SIZE_MAX, 0, NULL, &rbuf, &rbuf_size) >= 0);
assert_se(rbuf_size == sizeof(buf));
assert_se(memcmp(buf, rbuf, rbuf_size) == 0);
rbuf = mfree(rbuf);
assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, 128, 0, NULL, &rbuf, &rbuf_size) >= 0);
assert_se(rbuf_size == 128);
assert_se(memcmp(buf, rbuf, rbuf_size) == 0);
rbuf = mfree(rbuf);
assert_se(read_full_file_full(AT_FDCWD, fn, 1234, SIZE_MAX, 0, NULL, &rbuf, &rbuf_size) >= 0);
assert_se(rbuf_size == sizeof(buf) - 1234);
assert_se(memcmp(buf + 1234, rbuf, rbuf_size) == 0);
rbuf = mfree(rbuf);
assert_se(read_full_file_full(AT_FDCWD, fn, 2345, 777, 0, NULL, &rbuf, &rbuf_size) >= 0);
assert_se(rbuf_size == 777);
assert_se(memcmp(buf + 2345, rbuf, rbuf_size) == 0);
rbuf = mfree(rbuf);
assert_se(read_full_file_full(AT_FDCWD, fn, 4700, 20, 0, NULL, &rbuf, &rbuf_size) >= 0);
assert_se(rbuf_size == 11);
assert_se(memcmp(buf + 4700, rbuf, rbuf_size) == 0);
rbuf = mfree(rbuf);
assert_se(read_full_file_full(AT_FDCWD, fn, 10000, 99, 0, NULL, &rbuf, &rbuf_size) >= 0);
assert_se(rbuf_size == 0);
rbuf = mfree(rbuf);
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@ -990,7 +946,6 @@ int main(int argc, char *argv[]) {
test_read_line4();
test_read_nul_string();
test_read_full_file_socket();
test_read_full_file_offset_size();
return 0;
}

View File

@ -100,11 +100,7 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", argv[6]);
} else {
r = read_full_file_full(
AT_FDCWD, argv[6], UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&hash_sig, &hash_sig_size);
r = read_full_file_full(AT_FDCWD, argv[6], READ_FULL_FILE_CONNECT_SOCKET, NULL, &hash_sig, &hash_sig_size);
if (r < 0)
return log_error_errno(r, "Failed to read root hash signature: %m");
}

View File

@ -4,4 +4,5 @@ Name=veth99
[Network]
DHCP=yes
IPv6AcceptRA=yes
LinkLocalAddressing=yes
VRF=vrf99

View File

@ -3,5 +3,5 @@ Name=veth99
[Network]
DHCP=ipv4
LinkLocalAddressing=yes
LinkLocalAddressing=fallback
IPv6AcceptRA=no

View File

@ -3,7 +3,7 @@ Name=veth99
[Network]
DHCP=ipv4
LinkLocalAddressing=yes
LinkLocalAddressing=fallback
IPv6AcceptRA=no
[DHCPv4]

View File

@ -3428,8 +3428,8 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
'dhcp-client-use-dns-yes.network',
'dhcp-client-use-domains.network',
'dhcp-client-vrf.network',
'dhcp-client-with-ipv4ll-with-dhcp-server.network',
'dhcp-client-with-ipv4ll-without-dhcp-server.network',
'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network',
'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network',
'dhcp-client-with-static-address.network',
'dhcp-client.network',
'dhcp-server-decline.network',
@ -3925,6 +3925,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print('## ip address show vrf vrf99')
output = check_output('ip address show vrf vrf99')
print(output)
self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
self.assertRegex(output, 'inet6 .* scope link')
@ -3932,6 +3933,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print('## ip address show dev veth99')
output = check_output('ip address show dev veth99')
print(output)
self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)')
self.assertRegex(output, 'inet6 .* scope link')
@ -3940,6 +3942,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
output = check_output('ip route show vrf vrf99')
print(output)
self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
@ -3992,9 +3995,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
print(output)
self.assertRegex(output, 'onlink')
def test_dhcp_client_with_ipv4ll_with_dhcp_server(self):
def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
'dhcp-client-with-ipv4ll-with-dhcp-server.network')
'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network')
start_networkd()
self.wait_online(['veth-peer:carrier'])
start_dnsmasq(lease_time='2m')
@ -4029,9 +4032,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
search_words_in_dnsmasq_log('DHCPOFFER', show_all=True)
def test_dhcp_client_with_ipv4ll_without_dhcp_server(self):
def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
'dhcp-client-with-ipv4ll-without-dhcp-server.network')
'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network')
start_networkd()
self.wait_online(['veth99:degraded', 'veth-peer:routable'])