Compare commits
66 Commits
7477451b69
...
2e22a54f4e
Author | SHA1 | Date |
---|---|---|
Guilhem Lettron | 2e22a54f4e | |
Lennart Poettering | b7aa08ca15 | |
Zbigniew Jędrzejewski-Szmek | 41ab3b7a85 | |
Lennart Poettering | f9f8268ac6 | |
Lennart Poettering | ef560d8b06 | |
Lennart Poettering | 6b636c2d27 | |
Lennart Poettering | 8987afc4d1 | |
Lennart Poettering | 7a509acc29 | |
Lennart Poettering | e5ea9ed030 | |
Lennart Poettering | a3292ec8d7 | |
Lennart Poettering | 6093b2bb05 | |
Charles (Chas) Williams | c0dd326953 | |
Lennart Poettering | 53caaffdf4 | |
Lennart Poettering | 282bde1066 | |
Lennart Poettering | 9933a47808 | |
Lennart Poettering | b64cea6027 | |
Lennart Poettering | 22810041c2 | |
Leonid Bloch | 26601a2a17 | |
Lennart Poettering | e544601536 | |
Lennart Poettering | 8089643328 | |
Lennart Poettering | b350807200 | |
Lennart Poettering | 68765d94fe | |
Lennart Poettering | 3ecb3bdc93 | |
Lennart Poettering | ee880b37c1 | |
Lennart Poettering | d1b75241ba | |
Lennart Poettering | 90b15e18ee | |
Lennart Poettering | f8f3f9263e | |
Lennart Poettering | 298f466f15 | |
Lennart Poettering | 5ead4e85f6 | |
Lennart Poettering | 5f152f43d0 | |
Lennart Poettering | 5a795bff38 | |
Lennart Poettering | d1cf202374 | |
Paul Davey | 9f537ae310 | |
Lennart Poettering | eaadc03d61 | |
Lennart Poettering | b51d61fec6 | |
Christian Göttsche | a9dfac21ec | |
Lennart Poettering | 97a3e8d582 | |
Lennart Poettering | 68d58f3869 | |
Raphael | 6355715e5b | |
Jérémy Rosen | a652f050a7 | |
Zbigniew Jędrzejewski-Szmek | 206056cf01 | |
Yu Watanabe | e813de549b | |
lothrond | cfd54b6a2e | |
Zbigniew Jędrzejewski-Szmek | 23e5e79a51 | |
Yu Watanabe | 5ecb131d94 | |
Yu Watanabe | e4a1e68d7a | |
Zbigniew Jędrzejewski-Szmek | 2b1daf24dc | |
Zbigniew Jędrzejewski-Szmek | 8755dbad5b | |
Christian Göttsche | 80e7c84081 | |
Christian Göttsche | aeec5efab5 | |
Zbigniew Jędrzejewski-Szmek | 6e86b24db3 | |
Zbigniew Jędrzejewski-Szmek | fe7a6da8c5 | |
Kevin Kuehler | 943800f4e7 | |
Kevin Kuehler | 155a6234ea | |
Kevin Kuehler | 82d832b435 | |
Zbigniew Jędrzejewski-Szmek | f4331d0db2 | |
Zbigniew Jędrzejewski-Szmek | 130b812f9d | |
Zbigniew Jędrzejewski-Szmek | ddeb3f5d4b | |
Zbigniew Jędrzejewski-Szmek | 94a404cb03 | |
Zbigniew Jędrzejewski-Szmek | f9761a89a8 | |
Spencer Michaels | 15b82eecb6 | |
Spencer Michaels | ae474efc3f | |
Spencer Michaels | 10d0024a07 | |
Spencer Michaels | 6cd12ebcfe | |
Spencer Michaels | 65901c0fd1 | |
Spencer Michaels | 7fa23ab646 |
1
TODO
1
TODO
|
@ -701,7 +701,6 @@ Features:
|
|||
- allow multiple signal handlers per signal?
|
||||
- document chaining of signal handler for SIGCHLD and child handlers
|
||||
- define more intervals where we will shift wakeup intervals around in, 1h, 6h, 24h, ...
|
||||
- generate a failure of a default event loop is executed out-of-thread
|
||||
|
||||
* investigate endianness issues of UUID vs. GUID
|
||||
|
||||
|
|
|
@ -207,6 +207,10 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*:pvr*
|
|||
KEYBOARD_KEY_c1=!prog2 #graphics amplifier, undock-button event
|
||||
KEYBOARD_KEY_c2=!power #graphics amplifier, surprise undock event
|
||||
|
||||
# Alienware M17xR3 laptops
|
||||
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pnM17xR3:*
|
||||
KEYBOARD_KEY_89=ejectcd
|
||||
|
||||
###########################################################
|
||||
# Asus
|
||||
###########################################################
|
||||
|
|
|
@ -471,7 +471,7 @@ mouse:usb:v046dp4069:name:Logitech MX Master 2s:
|
|||
# Logitech MX Master 2S (via Bluetooth)
|
||||
# Horiz wheel has 14 stops, angle is rounded up
|
||||
mouse:bluetooth:v046dpb019:name:MX Master 2S Mouse:
|
||||
MOUSE_DPI=2000@2000
|
||||
MOUSE_DPI=1000@2000
|
||||
MOUSE_WHEEL_CLICK_ANGLE=15
|
||||
MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL=26
|
||||
MOUSE_WHEEL_CLICK_COUNT=24
|
||||
|
|
|
@ -139,6 +139,51 @@
|
|||
<literal>us</literal>. To turn off any kind of rate limiting,
|
||||
set either value to 0.</para>
|
||||
|
||||
<para>Note that the effective rate limit is multiplied with a
|
||||
factor derived from the available free disk space for the journal.
|
||||
Currently, this factor is calculated using the base 2 logarithm.</para>
|
||||
|
||||
<table>
|
||||
<title>Example <varname>RateLimitBurst=</varname> rate
|
||||
modifications by the available disk space</title>
|
||||
<tgroup cols='2'>
|
||||
<colspec colname='freespace' />
|
||||
<colspec colname='multiplier' />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Available Disk Space</entry>
|
||||
<entry>Burst Multiplier</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><= 1MB</entry>
|
||||
<entry>1</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><= 16MB</entry>
|
||||
<entry>2</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><= 256MB</entry>
|
||||
<entry>3</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><= 4GB</entry>
|
||||
<entry>4</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><= 64GB</entry>
|
||||
<entry>5</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><= 1TB</entry>
|
||||
<entry>6</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>If a service provides rate limits for itself through
|
||||
<varname>LogRateLimitIntervalSec=</varname> and/or <varname>LogRateLimitBurst=</varname>
|
||||
in <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
|
|
|
@ -393,6 +393,17 @@
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.cpu_affinity=</varname></term>
|
||||
|
||||
<listitem>
|
||||
<para>Overrides the CPU affinity mask for the service manager and the default for all child
|
||||
processes it forks. This takes precedence over <varname>CPUAffinity=</varname>, see
|
||||
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for details.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>modules_load=</varname></term>
|
||||
<term><varname>rd.modules_load=</varname></term>
|
||||
|
|
|
@ -214,6 +214,9 @@
|
|||
resolver is not capable of authenticating the server, so it is
|
||||
vulnerable to "man-in-the-middle" attacks.</para>
|
||||
|
||||
<para>Server Name Indication (SNI) can be used when opening a TLS connection.
|
||||
Entries in <varname>DNS=</varname> should be in format <literal>address#server_name</literal>.</para>
|
||||
|
||||
<para>In addition to this global DNSOverTLS setting
|
||||
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
also maintains per-link DNSOverTLS settings. For system DNS
|
||||
|
|
|
@ -371,7 +371,15 @@ manpages = [
|
|||
['sd_bus_wait', '3', [], ''],
|
||||
['sd_event_add_child',
|
||||
'3',
|
||||
['sd_event_child_handler_t', 'sd_event_source_get_child_pid'],
|
||||
['sd_event_add_child_pidfd',
|
||||
'sd_event_child_handler_t',
|
||||
'sd_event_source_get_child_pid',
|
||||
'sd_event_source_get_child_pidfd',
|
||||
'sd_event_source_get_child_pidfd_own',
|
||||
'sd_event_source_get_child_process_own',
|
||||
'sd_event_source_send_child_signal',
|
||||
'sd_event_source_set_child_pidfd_own',
|
||||
'sd_event_source_set_child_process_own'],
|
||||
''],
|
||||
['sd_event_add_defer',
|
||||
'3',
|
||||
|
|
|
@ -17,7 +17,14 @@
|
|||
|
||||
<refnamediv>
|
||||
<refname>sd_event_add_child</refname>
|
||||
<refname>sd_event_add_child_pidfd</refname>
|
||||
<refname>sd_event_source_get_child_pid</refname>
|
||||
<refname>sd_event_source_get_child_pidfd</refname>
|
||||
<refname>sd_event_source_get_child_pidfd_own</refname>
|
||||
<refname>sd_event_source_set_child_pidfd_own</refname>
|
||||
<refname>sd_event_source_get_child_process_own</refname>
|
||||
<refname>sd_event_source_set_child_process_own</refname>
|
||||
<refname>sd_event_source_send_child_signal</refname>
|
||||
<refname>sd_event_child_handler_t</refname>
|
||||
|
||||
<refpurpose>Add a child process state change event source to an event loop</refpurpose>
|
||||
|
@ -46,40 +53,77 @@
|
|||
<paramdef>void *<parameter>userdata</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_add_child_pidfd</function></funcdef>
|
||||
<paramdef>sd_event *<parameter>event</parameter></paramdef>
|
||||
<paramdef>sd_event_source **<parameter>source</parameter></paramdef>
|
||||
<paramdef>int <parameter>pidfd</parameter></paramdef>
|
||||
<paramdef>int <parameter>options</parameter></paramdef>
|
||||
<paramdef>sd_event_child_handler_t <parameter>handler</parameter></paramdef>
|
||||
<paramdef>void *<parameter>userdata</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_source_get_child_pid</function></funcdef>
|
||||
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
|
||||
<paramdef>pid_t *<parameter>pid</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_source_get_child_pidfd</function></funcdef>
|
||||
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_source_get_child_pidfd_own</function></funcdef>
|
||||
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_source_set_child_pidfd_own</function></funcdef>
|
||||
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
|
||||
<paramdef>int <parameter>own</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_source_get_child_process_own</function></funcdef>
|
||||
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_source_set_child_process_own</function></funcdef>
|
||||
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
|
||||
<paramdef>int <parameter>own</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_event_source_send_child_signal</function></funcdef>
|
||||
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
|
||||
<paramdef>int <parameter>sig</parameter></paramdef>
|
||||
<paramdef>const siginfo_t *<parameter>info</parameter></paramdef>
|
||||
<paramdef>unsigned <parameter>flags</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><function>sd_event_add_child()</function> adds a new child
|
||||
process state change event source to an event loop. The event loop
|
||||
object is specified in the <parameter>event</parameter> parameter,
|
||||
the event source object is returned in the
|
||||
<parameter>source</parameter> parameter. The
|
||||
<parameter>pid</parameter> parameter specifies the PID of the
|
||||
process to watch. The <parameter>handler</parameter> must
|
||||
reference a function to call when the process changes state. The
|
||||
handler function will be passed the
|
||||
<parameter>userdata</parameter> pointer, which may be chosen
|
||||
freely by the caller. The handler also receives a pointer to a
|
||||
<structname>siginfo_t</structname> structure containing
|
||||
information about the child process event. The
|
||||
<parameter>options</parameter> parameter determines which state
|
||||
changes will be watched for. It must contain an OR-ed mask of
|
||||
<constant>WEXITED</constant> (watch for the child process
|
||||
terminating), <constant>WSTOPPED</constant> (watch for the child
|
||||
process being stopped by a signal), and
|
||||
<constant>WCONTINUED</constant> (watch for the child process being
|
||||
resumed by a signal). See <citerefentry
|
||||
project='man-pages'><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
for further information.</para>
|
||||
<para><function>sd_event_add_child()</function> adds a new child process state change event source to an
|
||||
event loop. The event loop object is specified in the <parameter>event</parameter> parameter, the event
|
||||
source object is returned in the <parameter>source</parameter> parameter. The <parameter>pid</parameter>
|
||||
parameter specifies the PID of the process to watch, which must be a direct child process of the invoking
|
||||
process. The <parameter>handler</parameter> must reference a function to call when the process changes
|
||||
state. The handler function will be passed the <parameter>userdata</parameter> pointer, which may be
|
||||
chosen freely by the caller. The handler also receives a pointer to a <structname>siginfo_t</structname>
|
||||
structure containing information about the child process event. The <parameter>options</parameter>
|
||||
parameter determines which state changes will be watched for. It must contain an OR-ed mask of
|
||||
<constant>WEXITED</constant> (watch for the child process terminating), <constant>WSTOPPED</constant>
|
||||
(watch for the child process being stopped by a signal), and <constant>WCONTINUED</constant> (watch for
|
||||
the child process being resumed by a signal). See <citerefentry
|
||||
project='man-pages'><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
|
||||
further information.</para>
|
||||
|
||||
<para>Only a single handler may be installed for a specific
|
||||
child process. The handler is enabled for a single event
|
||||
|
@ -100,6 +144,12 @@
|
|||
<constant>SD_EVENT_OFF</constant> with
|
||||
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>The <constant>SIGCHLD</constant> signal must be blocked in all threads before this function is
|
||||
called (using <citerefentry
|
||||
project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry> or
|
||||
<citerefentry
|
||||
project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para>
|
||||
|
||||
<para>If the second parameter of
|
||||
<function>sd_event_add_child()</function> is passed as NULL no
|
||||
reference to the event source object is returned. In this case the
|
||||
|
@ -121,6 +171,17 @@
|
|||
processed first, it should leave the child processes for which
|
||||
child process state change event sources are installed unreaped.</para>
|
||||
|
||||
<para><function>sd_event_add_child_pidfd()</function> is similar to
|
||||
<function>sd_event_add_child()</function> but takes a file descriptor referencing the process ("pidfd")
|
||||
instead of the numeric PID. A suitable file descriptor may be acquired via <citerefentry
|
||||
project='man-pages'><refentrytitle>pidfd_open</refentrytitle><manvolnum>2</manvolnum></citerefentry> and
|
||||
related calls. The passed file descriptor is not closed when the event source is freed again, unless
|
||||
<function>sd_event_source_set_child_pidfd_own()</function> is used to turn this behaviour on. Note that
|
||||
regardless which of <function>sd_event_add_child()</function> and
|
||||
<function>sd_event_add_child_pidfd()</function> is used for allocating an event source, the watched
|
||||
process has to be a direct child process of the invoking process. Also in both cases
|
||||
<constant>SIGCHLD</constant> has to be blocked in the invoking process.</para>
|
||||
|
||||
<para><function>sd_event_source_get_child_pid()</function>
|
||||
retrieves the configured PID of a child process state change event
|
||||
source created previously with
|
||||
|
@ -129,6 +190,45 @@
|
|||
pointer to a <type>pid_t</type> variable to return the process ID
|
||||
in.
|
||||
</para>
|
||||
|
||||
<para><function>sd_event_source_get_child_pidfd()</function> retrieves the file descriptor referencing
|
||||
the watched process ("pidfd") if this functionality is available. On kernels that support the concept the
|
||||
event loop will make use of pidfds to watch child processes, regardless if the individual event sources
|
||||
are allocated via <function>sd_event_add_child()</function> or
|
||||
<function>sd_event_add_child_pidfd()</function>. If the latter call was used to allocate the event
|
||||
source, this function returns the file descriptor used for allocation. On kernels that do not support the
|
||||
pidfd concept this function will fail with <constant>EOPNOTSUPP</constant>. This call takes the event
|
||||
source object as the <parameter>source</parameter> parameter and returns the numeric file descriptor.
|
||||
</para>
|
||||
|
||||
<para><function>sd_event_source_get_child_pidfd_own()</function> may be used to query whether the pidfd
|
||||
the event source encapsulates shall be closed when the event source is freed. This function returns zero
|
||||
if the pidfd shall be left open, and positive if it shall be closed automatically. By default this
|
||||
setting defaults to on if the event source was allocated via <function>sd_event_add_child()</function>
|
||||
and off if it was allocated via <function>sd_event_add_child_pidfd()</function>. The
|
||||
<function>sd_event_source_set_child_pidfd_own()</function> function may be used to change the setting and
|
||||
takes a boolean parameter with the new setting.</para>
|
||||
|
||||
<para><function>sd_event_source_get_child_process_own()</function> may be used to query whether the
|
||||
process the event source watches shall be killed (with <constant>SIGKILL</constant>) and reaped when the
|
||||
event source is freed. This function returns zero if the process shell be left running, and positive if
|
||||
it shall be killed and reaped automatically. By default this setting defaults to off. The
|
||||
<function>sd_event_source_set_child_process_own()</function> function may be used to change the setting
|
||||
and takes a boolean parameter with the new setting. Note that currently if the calling process is
|
||||
terminated abnormally the watched process might survive even thought the event source ceases to
|
||||
exist. This behaviour might change eventually.</para>
|
||||
|
||||
<para><function>sd_event_source_send_child_signal()</function> may be used to send a UNIX signal to the
|
||||
watched process. If the pidfd concept is supported in the kernel, this is implemented via <citerefentry
|
||||
project='man-pages'><refentrytitle>pidfd_send_signal</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
and otherwise via <citerefentry
|
||||
project='man-pages'><refentrytitle>rt_sigqueueinfo</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
(or via <citerefentry
|
||||
project='man-pages'><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry> in case
|
||||
<parameter>info</parameter> is <constant>NULL</constant>). The specified parameters match those of these
|
||||
underlying system calls, except that the <parameter>info</parameter> is never modified (and is thus
|
||||
declared constant). Like for the underlying system calls, the <parameter>flags</parameter> parameter
|
||||
currently must be zero.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -165,8 +265,8 @@
|
|||
<varlistentry>
|
||||
<term><constant>-EBUSY</constant></term>
|
||||
|
||||
<listitem><para>A handler is already installed for this
|
||||
child process.</para></listitem>
|
||||
<listitem><para>A handler is already installed for this child process, or
|
||||
<constant>SIGCHLD</constant> is not blocked.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
|
@ -190,6 +290,12 @@
|
|||
<listitem><para>The passed event source is not a child process event source.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-EOPNOTSUPP</constant></term>
|
||||
|
||||
<listitem><para>A pidfd was requested but the kernel does not support this concept.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
@ -214,7 +320,13 @@
|
|||
<citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_floating</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
<citerefentry project='man-pages'><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>pidfd_open</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>pidfd_send_signal</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>rt_sigqueueinfo</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
|
|
@ -75,14 +75,13 @@
|
|||
project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
for further information.</para>
|
||||
|
||||
<para>Only a single handler may be installed for a specific
|
||||
signal. The signal will be unblocked by this call, and must be
|
||||
blocked before this function is called in all threads (using
|
||||
<para>Only a single handler may be installed for a specific signal. The signal must be blocked in all
|
||||
threads before this function is called (using <citerefentry
|
||||
project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry> or
|
||||
<citerefentry
|
||||
project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry>). If
|
||||
the handler is not specified (<parameter>handler</parameter> is
|
||||
<constant>NULL</constant>), a default handler which causes the
|
||||
program to exit cleanly will be used.</para>
|
||||
project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>). If
|
||||
the handler is not specified (<parameter>handler</parameter> is <constant>NULL</constant>), a default
|
||||
handler which causes the program to exit cleanly will be used.</para>
|
||||
|
||||
<para>By default, the event source is enabled permanently
|
||||
(<constant>SD_EVENT_ON</constant>), but this may be changed with
|
||||
|
@ -189,7 +188,9 @@
|
|||
<citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_event_source_set_floating</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
<citerefentry project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
<filename>hibernate.target</filename>,
|
||||
<filename>hybrid-sleep.target</filename>,
|
||||
<filename>suspend-then-hibernate.target</filename>,
|
||||
<filename>initrd.target</filename>,
|
||||
<filename>initrd-fs.target</filename>,
|
||||
<filename>initrd-root-device.target</filename>,
|
||||
<filename>initrd-root-fs.target</filename>,
|
||||
|
@ -202,14 +203,16 @@
|
|||
<varlistentry>
|
||||
<term><filename>default.target</filename></term>
|
||||
<listitem>
|
||||
<para>The default unit systemd starts at bootup. Usually,
|
||||
this should be aliased (symlinked) to
|
||||
<filename>multi-user.target</filename> or
|
||||
<filename>graphical.target</filename>.</para>
|
||||
<para>The default unit systemd starts at bootup. Usually, this should be aliased (symlinked) to
|
||||
<filename>multi-user.target</filename> or <filename>graphical.target</filename>. See
|
||||
<citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
||||
more discussion.</para>
|
||||
|
||||
<para>The default unit systemd starts at bootup can be
|
||||
overridden with the <varname>systemd.unit=</varname> kernel
|
||||
command line option.</para>
|
||||
<para>The default unit systemd starts at bootup can be overridden with the
|
||||
<varname>systemd.unit=</varname> kernel command line option, or more conveniently, with the short
|
||||
names like <varname>single</varname>, <varname>rescue</varname>, <varname>1</varname>,
|
||||
<varname>3</varname>, <varname>5</varname>, …; see
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
@ -341,6 +344,15 @@
|
|||
is active as long as the system is running.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>initrd.target</filename></term>
|
||||
<listitem>
|
||||
<para>This is the default target in the initramfs, similar to <filename>default.target</filename>
|
||||
in the main system. It is used to mount the real root and transition to it. See
|
||||
<citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
||||
more discussion.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>initrd-fs.target</filename></term>
|
||||
<listitem>
|
||||
|
|
12
meson.build
12
meson.build
|
@ -517,6 +517,18 @@ foreach ident : [
|
|||
#include <unistd.h>'''],
|
||||
['get_mempolicy', '''#include <stdlib.h>
|
||||
#include <unistd.h>'''],
|
||||
['pidfd_send_signal', '''#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>'''],
|
||||
['pidfd_open', '''#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>'''],
|
||||
['rt_sigqueueinfo', '''#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>'''],
|
||||
]
|
||||
|
||||
have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
|
||||
|
|
|
@ -86,21 +86,18 @@ unsigned long cap_last_cap(void) {
|
|||
int capability_update_inherited_set(cap_t caps, uint64_t set) {
|
||||
unsigned long i;
|
||||
|
||||
/* Add capabilities in the set to the inherited caps. Do not apply
|
||||
* them yet. */
|
||||
/* Add capabilities in the set to the inherited caps, drops capabilities not in the set.
|
||||
* Do not apply them yet. */
|
||||
|
||||
for (i = 0; i <= cap_last_cap(); i++) {
|
||||
|
||||
if (set & (UINT64_C(1) << i)) {
|
||||
cap_flag_value_t flag = set & (UINT64_C(1) << i) ? CAP_SET : CAP_CLEAR;
|
||||
cap_value_t v;
|
||||
|
||||
v = (cap_value_t) i;
|
||||
|
||||
/* Make the capability inheritable. */
|
||||
if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, CAP_SET) < 0)
|
||||
if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, flag) < 0)
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -132,6 +129,17 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
|
|||
/* Add the capability to the ambient set. */
|
||||
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0)
|
||||
return -errno;
|
||||
} else {
|
||||
|
||||
/* Drop the capability so we don't inherit capabilities we didn't ask for. */
|
||||
r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, i, 0, 0);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (r)
|
||||
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, i, 0, 0) < 0)
|
||||
return -errno;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "missing_syscall.h"
|
||||
#include "mountpoint-util.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "selinux-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
@ -372,7 +373,15 @@ static int fd_copy_symlink(
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (symlinkat(target, dt, to) < 0)
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, S_IFLNK);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
r = symlinkat(target, dt, to);
|
||||
if (copy_flags & COPY_MAC_CREATE)
|
||||
mac_selinux_create_file_clear();
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (fchownat(dt, to,
|
||||
|
@ -408,7 +417,14 @@ static int fd_copy_regular(
|
|||
if (fdf < 0)
|
||||
return -errno;
|
||||
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, S_IFREG);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777);
|
||||
if (copy_flags & COPY_MAC_CREATE)
|
||||
mac_selinux_create_file_clear();
|
||||
if (fdt < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -457,7 +473,14 @@ static int fd_copy_fifo(
|
|||
assert(st);
|
||||
assert(to);
|
||||
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, S_IFIFO);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
r = mkfifoat(dt, to, st->st_mode & 07777);
|
||||
if (copy_flags & COPY_MAC_CREATE)
|
||||
mac_selinux_create_file_clear();
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -488,7 +511,14 @@ static int fd_copy_node(
|
|||
assert(st);
|
||||
assert(to);
|
||||
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, st->st_mode & S_IFMT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
r = mknodat(dt, to, st->st_mode, st->st_rdev);
|
||||
if (copy_flags & COPY_MAC_CREATE)
|
||||
mac_selinux_create_file_clear();
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -556,6 +586,9 @@ static int fd_copy_directory(
|
|||
if (exists)
|
||||
created = false;
|
||||
else {
|
||||
if (copy_flags & COPY_MAC_CREATE)
|
||||
r = mkdirat_label(dt, to, st->st_mode & 07777);
|
||||
else
|
||||
r = mkdirat(dt, to, st->st_mode & 07777);
|
||||
if (r >= 0)
|
||||
created = true;
|
||||
|
@ -796,7 +829,14 @@ int copy_file_full(
|
|||
assert(to);
|
||||
|
||||
RUN_WITH_UMASK(0000) {
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare(to, S_IFREG);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
|
||||
if (copy_flags & COPY_MAC_CREATE)
|
||||
mac_selinux_create_file_clear();
|
||||
if (fdt < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
@ -850,13 +890,29 @@ int copy_file_atomic_full(
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare(to, S_IFREG);
|
||||
if (r < 0) {
|
||||
t = mfree(t);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
fdt = open(t, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600);
|
||||
if (copy_flags & COPY_MAC_CREATE)
|
||||
mac_selinux_create_file_clear();
|
||||
if (fdt < 0) {
|
||||
t = mfree(t);
|
||||
return -errno;
|
||||
}
|
||||
} else {
|
||||
if (copy_flags & COPY_MAC_CREATE) {
|
||||
r = mac_selinux_create_file_prepare(to, S_IFREG);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
fdt = open_tmpfile_linkable(to, O_WRONLY|O_CLOEXEC, &t);
|
||||
if (copy_flags & COPY_MAC_CREATE)
|
||||
mac_selinux_create_file_clear();
|
||||
if (fdt < 0)
|
||||
return fdt;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ typedef enum CopyFlags {
|
|||
COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
|
||||
COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
|
||||
COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
|
||||
COPY_MAC_CREATE = 1 << 7, /* Create files with the correct MAC label (currently SELinux only) */
|
||||
} CopyFlags;
|
||||
|
||||
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
|
||||
|
|
|
@ -101,3 +101,11 @@ static inline bool ERRNO_IS_PRIVILEGE(int r) {
|
|||
EACCES,
|
||||
EPERM);
|
||||
}
|
||||
|
||||
/* Three difference errors for "not enough disk space" */
|
||||
static inline bool ERRNO_IS_DISK_SPACE(int r) {
|
||||
return IN_SET(abs(r),
|
||||
ENOSPC,
|
||||
EDQUOT,
|
||||
EFBIG);
|
||||
}
|
||||
|
|
|
@ -80,14 +80,21 @@ static inline void* explicit_bzero_safe(void *p, size_t l) {
|
|||
void *explicit_bzero_safe(void *p, size_t l);
|
||||
#endif
|
||||
|
||||
static inline void erase_and_freep(void *p) {
|
||||
void *ptr = *(void**) p;
|
||||
static inline void* erase_and_free(void *p) {
|
||||
size_t l;
|
||||
|
||||
if (ptr) {
|
||||
size_t l = malloc_usable_size(ptr);
|
||||
explicit_bzero_safe(ptr, l);
|
||||
free(ptr);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
l = malloc_usable_size(p);
|
||||
explicit_bzero_safe(p, l);
|
||||
free(p);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void erase_and_freep(void *p) {
|
||||
erase_and_free(*(void**) p);
|
||||
}
|
||||
|
||||
/* Use with _cleanup_ to erase a single 'char' when leaving scope */
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef ARCH_MIPS
|
||||
|
@ -524,3 +526,45 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask,
|
|||
|
||||
#define get_mempolicy missing_get_mempolicy
|
||||
#endif
|
||||
|
||||
#if !HAVE_PIDFD_OPEN
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_pidfd_open && __NR_pidfd_open > 0)
|
||||
# if defined __NR_pidfd_open
|
||||
# undef __NR_pidfd_open
|
||||
# endif
|
||||
# define __NR_pidfd_open 434
|
||||
#endif
|
||||
static inline int pidfd_open(pid_t pid, unsigned flags) {
|
||||
#ifdef __NR_pidfd_open
|
||||
return syscall(__NR_pidfd_open, pid, flags);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !HAVE_PIDFD_SEND_SIGNAL
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_pidfd_send_signal && __NR_pidfd_send_signal > 0)
|
||||
# if defined __NR_pidfd_send_signal
|
||||
# undef __NR_pidfd_send_signal
|
||||
# endif
|
||||
# define __NR_pidfd_send_signal 424
|
||||
#endif
|
||||
static inline int pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) {
|
||||
#ifdef __NR_pidfd_open
|
||||
return syscall(__NR_pidfd_send_signal, fd, sig, info, flags);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !HAVE_RT_SIGQUEUEINFO
|
||||
static inline int rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info) {
|
||||
return syscall(__NR_rt_sigqueueinfo, tgid, sig, info);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -50,6 +50,10 @@ static inline void* ordered_set_remove(OrderedSet *s, void *p) {
|
|||
return ordered_hashmap_remove((OrderedHashmap*) s, p);
|
||||
}
|
||||
|
||||
static inline void* ordered_set_first(OrderedSet *s) {
|
||||
return ordered_hashmap_first((OrderedHashmap*) s);
|
||||
}
|
||||
|
||||
static inline void* ordered_set_steal_first(OrderedSet *s) {
|
||||
return ordered_hashmap_steal_first((OrderedHashmap*) s);
|
||||
}
|
||||
|
|
|
@ -365,7 +365,6 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
|
|||
unsigned long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret_u);
|
||||
assert(base <= 16);
|
||||
|
||||
/* strtoul() is happy to parse negative values, and silently
|
||||
|
@ -389,7 +388,9 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
|
|||
if ((unsigned long) (unsigned) l != l)
|
||||
return -ERANGE;
|
||||
|
||||
if (ret_u)
|
||||
*ret_u = (unsigned) l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -398,7 +399,6 @@ int safe_atoi(const char *s, int *ret_i) {
|
|||
long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret_i);
|
||||
|
||||
errno = 0;
|
||||
l = strtol(s, &x, 0);
|
||||
|
@ -409,7 +409,9 @@ int safe_atoi(const char *s, int *ret_i) {
|
|||
if ((long) (int) l != l)
|
||||
return -ERANGE;
|
||||
|
||||
if (ret_i)
|
||||
*ret_i = (int) l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -418,7 +420,6 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
|
|||
unsigned long long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret_llu);
|
||||
|
||||
s += strspn(s, WHITESPACE);
|
||||
|
||||
|
@ -431,7 +432,9 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
|
|||
if (*s == '-')
|
||||
return -ERANGE;
|
||||
|
||||
if (ret_llu)
|
||||
*ret_llu = l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -440,7 +443,6 @@ int safe_atolli(const char *s, long long int *ret_lli) {
|
|||
long long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret_lli);
|
||||
|
||||
errno = 0;
|
||||
l = strtoll(s, &x, 0);
|
||||
|
@ -449,7 +451,9 @@ int safe_atolli(const char *s, long long int *ret_lli) {
|
|||
if (!x || x == s || *x != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (ret_lli)
|
||||
*ret_lli = l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -458,7 +462,6 @@ int safe_atou8(const char *s, uint8_t *ret) {
|
|||
unsigned long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
s += strspn(s, WHITESPACE);
|
||||
|
||||
|
@ -473,6 +476,7 @@ int safe_atou8(const char *s, uint8_t *ret) {
|
|||
if ((unsigned long) (uint8_t) l != l)
|
||||
return -ERANGE;
|
||||
|
||||
if (ret)
|
||||
*ret = (uint8_t) l;
|
||||
return 0;
|
||||
}
|
||||
|
@ -507,7 +511,6 @@ int safe_atoi16(const char *s, int16_t *ret) {
|
|||
long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
errno = 0;
|
||||
l = strtol(s, &x, 0);
|
||||
|
@ -518,7 +521,9 @@ int safe_atoi16(const char *s, int16_t *ret) {
|
|||
if ((long) (int16_t) l != l)
|
||||
return -ERANGE;
|
||||
|
||||
if (ret)
|
||||
*ret = (int16_t) l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -528,7 +533,6 @@ int safe_atod(const char *s, double *ret_d) {
|
|||
double d = 0;
|
||||
|
||||
assert(s);
|
||||
assert(ret_d);
|
||||
|
||||
loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
|
||||
if (loc == (locale_t) 0)
|
||||
|
@ -541,7 +545,9 @@ int safe_atod(const char *s, double *ret_d) {
|
|||
if (!x || x == s || *x != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (ret_d)
|
||||
*ret_d = (double) d;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "rlimit-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "terminal-util.h"
|
||||
|
@ -1337,6 +1338,13 @@ int safe_fork_full(
|
|||
log_full_errno(prio, r, "Failed to connect stdin/stdout to /dev/null: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
} else if (flags & FORK_STDOUT_TO_STDERR) {
|
||||
|
||||
if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) {
|
||||
log_full_errno(prio, r, "Failed to connect stdout to stderr: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FORK_RLIMIT_NOFILE_SAFE) {
|
||||
|
@ -1488,6 +1496,38 @@ int set_oom_score_adjust(int value) {
|
|||
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||
}
|
||||
|
||||
int pidfd_get_pid(int fd, pid_t *ret) {
|
||||
char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
|
||||
_cleanup_free_ char *fdinfo = NULL;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
if (fd < 0)
|
||||
return -EBADF;
|
||||
|
||||
xsprintf(path, "/proc/self/fdinfo/%i", fd);
|
||||
|
||||
r = read_full_file(path, &fdinfo, NULL);
|
||||
if (r == -ENOENT) /* if fdinfo doesn't exist we assume the process does not exist */
|
||||
return -ESRCH;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p = startswith(fdinfo, "Pid:");
|
||||
if (!p) {
|
||||
p = strstr(fdinfo, "\nPid:");
|
||||
if (!p)
|
||||
return -ENOTTY; /* not a pidfd? */
|
||||
|
||||
p += 5;
|
||||
}
|
||||
|
||||
p += strspn(p, WHITESPACE);
|
||||
p[strcspn(p, WHITESPACE)] = 0;
|
||||
|
||||
return parse_pid(p, ret);
|
||||
}
|
||||
|
||||
static const char *const ioprio_class_table[] = {
|
||||
[IOPRIO_CLASS_NONE] = "none",
|
||||
[IOPRIO_CLASS_RT] = "realtime",
|
||||
|
|
|
@ -157,6 +157,7 @@ typedef enum ForkFlags {
|
|||
FORK_NEW_MOUNTNS = 1 << 7, /* Run child in its own mount namespace */
|
||||
FORK_MOUNTNS_SLAVE = 1 << 8, /* Make child's mount namespace MS_SLAVE */
|
||||
FORK_RLIMIT_NOFILE_SAFE = 1 << 9, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
|
||||
FORK_STDOUT_TO_STDERR = 1 << 10, /* Make stdout a copy of stderr */
|
||||
} ForkFlags;
|
||||
|
||||
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
|
||||
|
@ -197,3 +198,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
|
|||
(pid) = 0; \
|
||||
_pid_; \
|
||||
})
|
||||
|
||||
int pidfd_get_pid(int fd, pid_t *ret);
|
||||
|
|
|
@ -107,6 +107,26 @@ void mac_selinux_finish(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void mac_selinux_reload(void) {
|
||||
|
||||
#if HAVE_SELINUX
|
||||
struct selabel_handle *backup_label_hnd;
|
||||
|
||||
if (!label_hnd)
|
||||
return;
|
||||
|
||||
backup_label_hnd = TAKE_PTR(label_hnd);
|
||||
|
||||
/* try to initialize new handle
|
||||
* on success close backup
|
||||
* on failure restore backup */
|
||||
if (mac_selinux_init() == 0)
|
||||
selabel_close(backup_label_hnd);
|
||||
else
|
||||
label_hnd = backup_label_hnd;
|
||||
#endif
|
||||
}
|
||||
|
||||
int mac_selinux_fix(const char *path, LabelFixFlags flags) {
|
||||
|
||||
#if HAVE_SELINUX
|
||||
|
|
|
@ -13,6 +13,7 @@ void mac_selinux_retest(void);
|
|||
|
||||
int mac_selinux_init(void);
|
||||
void mac_selinux_finish(void);
|
||||
void mac_selinux_reload(void);
|
||||
|
||||
int mac_selinux_fix(const char *path, LabelFixFlags flags);
|
||||
int mac_selinux_apply(const char *path, const char *label);
|
||||
|
|
|
@ -287,3 +287,18 @@ int signal_from_string(const char *s) {
|
|||
void nop_signal_handler(int sig) {
|
||||
/* nothing here */
|
||||
}
|
||||
|
||||
int signal_is_blocked(int sig) {
|
||||
sigset_t ss;
|
||||
int r;
|
||||
|
||||
r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
|
||||
if (r != 0)
|
||||
return -r;
|
||||
|
||||
r = sigismember(&ss, sig);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -41,3 +41,5 @@ static inline const char* signal_to_string_with_check(int n) {
|
|||
|
||||
return signal_to_string(n);
|
||||
}
|
||||
|
||||
int signal_is_blocked(int sig);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#define SPECIAL_DEFAULT_TARGET "default.target"
|
||||
#define SPECIAL_INITRD_TARGET "initrd.target"
|
||||
|
||||
/* Shutdown targets */
|
||||
#define SPECIAL_UMOUNT_TARGET "umount.target"
|
||||
|
|
|
@ -1064,3 +1064,13 @@ bool string_is_safe(const char *p) {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
char* string_erase(char *x) {
|
||||
if (!x)
|
||||
return NULL;
|
||||
|
||||
/* A delicious drop of snake-oil! To be called on memory where we stored passphrases or so, after we
|
||||
* used them. */
|
||||
explicit_bzero_safe(x, strlen(x));
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -278,3 +278,5 @@ static inline char* str_realloc(char **p) {
|
|||
|
||||
return (*p = t);
|
||||
}
|
||||
|
||||
char* string_erase(char *x);
|
||||
|
|
|
@ -19,49 +19,59 @@
|
|||
#include "tmpfile-util.h"
|
||||
#include "umask-util.h"
|
||||
|
||||
int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
|
||||
FILE *f;
|
||||
char *t;
|
||||
int r, fd;
|
||||
|
||||
assert(path);
|
||||
assert(_f);
|
||||
assert(_temp_path);
|
||||
int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r;
|
||||
|
||||
if (path) {
|
||||
r = tempfn_xxxxxx(path, NULL, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
const char *d;
|
||||
|
||||
r = tmp_dir(&d);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t = path_join(d, "XXXXXX");
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fd = mkostemp_safe(t);
|
||||
if (fd < 0) {
|
||||
free(t);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* This assumes that returned FILE object is short-lived and used within the same single-threaded
|
||||
* context and never shared externally, hence locking is not necessary. */
|
||||
|
||||
r = fdopen_unlocked(fd, "w", &f);
|
||||
if (r < 0) {
|
||||
unlink(t);
|
||||
free(t);
|
||||
safe_close(fd);
|
||||
(void) unlink(t);
|
||||
return r;
|
||||
}
|
||||
|
||||
*_f = f;
|
||||
*_temp_path = t;
|
||||
TAKE_FD(fd);
|
||||
|
||||
if (ret_f)
|
||||
*ret_f = TAKE_PTR(f);
|
||||
|
||||
if (ret_temp_path)
|
||||
*ret_temp_path = TAKE_PTR(t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is much like mkostemp() but is subject to umask(). */
|
||||
int mkostemp_safe(char *pattern) {
|
||||
_unused_ _cleanup_umask_ mode_t u = umask(0077);
|
||||
int fd;
|
||||
|
||||
assert(pattern);
|
||||
|
||||
RUN_WITH_UMASK(0077)
|
||||
fd = mkostemp(pattern, O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
|
|
@ -84,7 +84,7 @@ char *getusername_malloc(void) {
|
|||
return uid_to_name(getuid());
|
||||
}
|
||||
|
||||
static bool is_nologin_shell(const char *shell) {
|
||||
bool is_nologin_shell(const char *shell) {
|
||||
|
||||
return PATH_IN_SET(shell,
|
||||
/* 'nologin' is the friendliest way to disable logins for a user account. It prints a nice
|
||||
|
|
|
@ -57,6 +57,14 @@ int take_etc_passwd_lock(const char *root);
|
|||
|
||||
#define ETC_PASSWD_LOCK_PATH "/etc/.pwd.lock"
|
||||
|
||||
static inline bool uid_is_system(uid_t uid) {
|
||||
return uid <= SYSTEM_UID_MAX;
|
||||
}
|
||||
|
||||
static inline bool gid_is_system(gid_t gid) {
|
||||
return gid <= SYSTEM_GID_MAX;
|
||||
}
|
||||
|
||||
static inline bool uid_is_dynamic(uid_t uid) {
|
||||
return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
|
||||
}
|
||||
|
@ -65,12 +73,12 @@ static inline bool gid_is_dynamic(gid_t gid) {
|
|||
return uid_is_dynamic((uid_t) gid);
|
||||
}
|
||||
|
||||
static inline bool uid_is_system(uid_t uid) {
|
||||
return uid <= SYSTEM_UID_MAX;
|
||||
static inline bool uid_is_container(uid_t uid) {
|
||||
return CONTAINER_UID_BASE_MIN <= uid && uid <= CONTAINER_UID_BASE_MAX;
|
||||
}
|
||||
|
||||
static inline bool gid_is_system(gid_t gid) {
|
||||
return gid <= SYSTEM_GID_MAX;
|
||||
static inline bool gid_is_container(gid_t gid) {
|
||||
return uid_is_container((uid_t) gid);
|
||||
}
|
||||
|
||||
/* The following macros add 1 when converting things, since UID 0 is a valid UID, while the pointer
|
||||
|
@ -127,3 +135,5 @@ int putsgent_sane(const struct sgrp *sg, FILE *stream);
|
|||
#endif
|
||||
|
||||
int make_salt(char **ret);
|
||||
|
||||
bool is_nologin_shell(const char *shell);
|
||||
|
|
|
@ -32,7 +32,7 @@ enum loader_type {
|
|||
};
|
||||
|
||||
typedef struct {
|
||||
CHAR16 *id; /* The identifier for this entry (note that this id is not necessarily unique though!) */
|
||||
CHAR16 *id; /* The unique identifier for this entry */
|
||||
CHAR16 *title_show;
|
||||
CHAR16 *title;
|
||||
CHAR16 *version;
|
||||
|
@ -1310,7 +1310,6 @@ static VOID config_entry_add_from_file(
|
|||
CHAR8 *line;
|
||||
UINTN pos = 0;
|
||||
CHAR8 *key, *value;
|
||||
UINTN len;
|
||||
EFI_STATUS err;
|
||||
EFI_FILE_HANDLE handle;
|
||||
_cleanup_freepool_ CHAR16 *initrd = NULL;
|
||||
|
@ -1431,10 +1430,6 @@ static VOID config_entry_add_from_file(
|
|||
|
||||
entry->device = device;
|
||||
entry->id = StrDuplicate(file);
|
||||
len = StrLen(entry->id);
|
||||
/* remove ".conf" */
|
||||
if (len > 5)
|
||||
entry->id[len - 5] = '\0';
|
||||
StrLwr(entry->id);
|
||||
|
||||
config_add_entry(config, entry);
|
||||
|
@ -1775,7 +1770,8 @@ static ConfigEntry *config_entry_add_loader(
|
|||
CHAR16 *id,
|
||||
CHAR16 key,
|
||||
CHAR16 *title,
|
||||
CHAR16 *loader) {
|
||||
CHAR16 *loader,
|
||||
CHAR16 *version) {
|
||||
|
||||
ConfigEntry *entry;
|
||||
|
||||
|
@ -1783,6 +1779,7 @@ static ConfigEntry *config_entry_add_loader(
|
|||
*entry = (ConfigEntry) {
|
||||
.type = type,
|
||||
.title = StrDuplicate(title),
|
||||
.version = StrDuplicate(version),
|
||||
.device = device,
|
||||
.loader = StrDuplicate(loader),
|
||||
.id = StrDuplicate(id),
|
||||
|
@ -1840,7 +1837,7 @@ static BOOLEAN config_entry_add_loader_auto(
|
|||
return FALSE;
|
||||
uefi_call_wrapper(handle->Close, 1, handle);
|
||||
|
||||
entry = config_entry_add_loader(config, device, LOADER_UNDEFINED, id, key, title, loader);
|
||||
entry = config_entry_add_loader(config, device, LOADER_UNDEFINED, id, key, title, loader, NULL);
|
||||
if (!entry)
|
||||
return FALSE;
|
||||
|
||||
|
@ -1908,10 +1905,12 @@ static VOID config_entry_add_linux(
|
|||
CHAR8 *line;
|
||||
UINTN pos = 0;
|
||||
CHAR8 *key, *value;
|
||||
CHAR16 *os_name_pretty = NULL;
|
||||
CHAR16 *os_name = NULL;
|
||||
CHAR16 *os_id = NULL;
|
||||
CHAR16 *os_version = NULL;
|
||||
CHAR16 *os_build = NULL;
|
||||
CHAR16 *os_version_id = NULL;
|
||||
CHAR16 *os_build_id = NULL;
|
||||
|
||||
err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf);
|
||||
if (bufsize == 0 || EFI_ERROR(err))
|
||||
|
@ -1927,6 +1926,8 @@ static VOID config_entry_add_linux(
|
|||
continue;
|
||||
if (StriCmp(f->FileName + len - 4, L".efi") != 0)
|
||||
continue;
|
||||
if (StrnCmp(f->FileName, L"auto-", 5) == 0)
|
||||
continue;
|
||||
|
||||
/* look for .osrel and .cmdline sections in the .efi binary */
|
||||
err = pe_file_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs);
|
||||
|
@ -1940,6 +1941,12 @@ static VOID config_entry_add_linux(
|
|||
/* read properties from the embedded os-release file */
|
||||
while ((line = line_get_key_value(content, (CHAR8 *)"=", &pos, &key, &value))) {
|
||||
if (strcmpa((CHAR8 *)"PRETTY_NAME", key) == 0) {
|
||||
FreePool(os_name_pretty);
|
||||
os_name_pretty = stra_to_str(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmpa((CHAR8 *)"NAME", key) == 0) {
|
||||
FreePool(os_name);
|
||||
os_name = stra_to_str(value);
|
||||
continue;
|
||||
|
@ -1957,20 +1964,27 @@ static VOID config_entry_add_linux(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (strcmpa((CHAR8 *)"VERSION_ID", key) == 0) {
|
||||
FreePool(os_version_id);
|
||||
os_version_id = stra_to_str(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmpa((CHAR8 *)"BUILD_ID", key) == 0) {
|
||||
FreePool(os_build);
|
||||
os_build = stra_to_str(value);
|
||||
FreePool(os_build_id);
|
||||
os_build_id = stra_to_str(value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (os_name && os_id && (os_version || os_build)) {
|
||||
_cleanup_freepool_ CHAR16 *conf = NULL, *path = NULL;
|
||||
if ((os_name_pretty || os_name) && os_id && (os_version || os_version_id || os_build_id)) {
|
||||
_cleanup_freepool_ CHAR16 *path = NULL;
|
||||
|
||||
conf = PoolPrint(L"%s-%s", os_id, os_version ? : os_build);
|
||||
path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName);
|
||||
|
||||
entry = config_entry_add_loader(config, device, LOADER_LINUX, conf, 'l', os_name, path);
|
||||
entry = config_entry_add_loader(config, device, LOADER_LINUX, f->FileName, 'l',
|
||||
os_name_pretty ? : (os_name ? : os_id), path,
|
||||
os_version ? : (os_version_id ? : os_build_id));
|
||||
|
||||
FreePool(content);
|
||||
content = NULL;
|
||||
|
@ -1989,10 +2003,12 @@ static VOID config_entry_add_linux(
|
|||
config_entry_parse_tries(entry, L"\\EFI\\Linux", f->FileName, L".efi");
|
||||
}
|
||||
|
||||
FreePool(os_name_pretty);
|
||||
FreePool(os_name);
|
||||
FreePool(os_id);
|
||||
FreePool(os_version);
|
||||
FreePool(os_build);
|
||||
FreePool(os_version_id);
|
||||
FreePool(os_build_id);
|
||||
FreePool(content);
|
||||
}
|
||||
|
||||
|
@ -2453,6 +2469,12 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
|||
UINT64 key;
|
||||
|
||||
err = console_key_read(&key, FALSE);
|
||||
|
||||
if (err == EFI_NOT_READY) {
|
||||
uefi_call_wrapper(BS->Stall, 1, 100 * 1000);
|
||||
err = console_key_read(&key, FALSE);
|
||||
}
|
||||
|
||||
if (!EFI_ERROR(err)) {
|
||||
INT16 idx;
|
||||
|
||||
|
|
|
@ -3595,8 +3595,7 @@ static int exec_child(
|
|||
|
||||
/* This is done before enforce_user, but ambient set
|
||||
* does not survive over setresuid() if keep_caps is not set. */
|
||||
if (!needs_ambient_hack &&
|
||||
context->capability_ambient_set != 0) {
|
||||
if (!needs_ambient_hack) {
|
||||
r = capability_ambient_set_apply(context->capability_ambient_set, true);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_CAPABILITIES;
|
||||
|
|
|
@ -475,6 +475,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
|||
if (arg_default_timeout_start_usec <= 0)
|
||||
arg_default_timeout_start_usec = USEC_INFINITY;
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.cpu_affinity")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = parse_cpu_set(value, &arg_cpu_affinity);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Faile to parse CPU affinity mask '%s', ignoring: %m", value);
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.watchdog_device")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
|
@ -1738,6 +1747,8 @@ static int invoke_main_loop(
|
|||
saved_log_level = m->log_level_overridden ? log_get_max_level() : -1;
|
||||
saved_log_target = m->log_target_overridden ? log_get_target() : _LOG_TARGET_INVALID;
|
||||
|
||||
mac_selinux_reload();
|
||||
|
||||
(void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
|
||||
|
||||
set_manager_defaults(m);
|
||||
|
@ -1986,20 +1997,36 @@ static int do_queue_default_job(
|
|||
const char **ret_error_message) {
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
const char* default_unit;
|
||||
Job *default_unit_job;
|
||||
Unit *target = NULL;
|
||||
int r;
|
||||
|
||||
log_debug("Activating default unit: %s", arg_default_unit);
|
||||
if (arg_default_unit)
|
||||
default_unit = arg_default_unit;
|
||||
else if (in_initrd())
|
||||
default_unit = SPECIAL_INITRD_TARGET;
|
||||
else
|
||||
default_unit = SPECIAL_DEFAULT_TARGET;
|
||||
|
||||
r = manager_load_startable_unit_or_warn(m, arg_default_unit, NULL, &target);
|
||||
log_debug("Activating default unit: %s", default_unit);
|
||||
|
||||
r = manager_load_startable_unit_or_warn(m, default_unit, NULL, &target);
|
||||
if (r < 0 && in_initrd() && !arg_default_unit) {
|
||||
/* Fall back to default.target, which we used to always use by default. Only do this if no
|
||||
* explicit configuration was given. */
|
||||
|
||||
log_info("Falling back to " SPECIAL_DEFAULT_TARGET ".");
|
||||
|
||||
r = manager_load_startable_unit_or_warn(m, SPECIAL_DEFAULT_TARGET, NULL, &target);
|
||||
}
|
||||
if (r < 0) {
|
||||
log_info("Falling back to rescue target: " SPECIAL_RESCUE_TARGET);
|
||||
log_info("Falling back to " SPECIAL_RESCUE_TARGET ".");
|
||||
|
||||
r = manager_load_startable_unit_or_warn(m, SPECIAL_RESCUE_TARGET, NULL, &target);
|
||||
if (r < 0) {
|
||||
*ret_error_message = r == -ERFKILL ? "Rescue target masked"
|
||||
: "Failed to load rescue target";
|
||||
*ret_error_message = r == -ERFKILL ? SPECIAL_RESCUE_TARGET " masked"
|
||||
: "Failed to load " SPECIAL_RESCUE_TARGET;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
@ -2211,15 +2238,6 @@ static int load_configuration(
|
|||
return r;
|
||||
}
|
||||
|
||||
/* Initialize default unit */
|
||||
if (!arg_default_unit) {
|
||||
arg_default_unit = strdup(SPECIAL_DEFAULT_TARGET);
|
||||
if (!arg_default_unit) {
|
||||
*ret_error_message = "Failed to set default unit";
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the show status setting if it hasn't been set explicitly yet */
|
||||
if (arg_show_status == _SHOW_STATUS_INVALID)
|
||||
arg_show_status = SHOW_STATUS_YES;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "umask-util.h"
|
||||
#include "user-util.h"
|
||||
|
||||
|
@ -1640,6 +1641,44 @@ int temporary_filesystem_add(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int make_tmp_prefix(const char *prefix) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int r;
|
||||
|
||||
/* Don't do anything unless we know the dir is actually missing */
|
||||
r = access(prefix, F_OK);
|
||||
if (r >= 0)
|
||||
return 0;
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
r = mkdir_parents(prefix, 0755);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = tempfn_random(prefix, NULL, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mkdir(t, 0777) < 0)
|
||||
return -errno;
|
||||
|
||||
if (chmod(t, 01777) < 0) {
|
||||
r = -errno;
|
||||
(void) rmdir(t);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (rename(t, prefix) < 0) {
|
||||
r = -errno;
|
||||
(void) rmdir(t);
|
||||
return r == -EEXIST ? 0 : r; /* it's fine if someone else created the dir by now */
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) {
|
||||
_cleanup_free_ char *x = NULL;
|
||||
char bid[SD_ID128_STRING_MAX];
|
||||
|
@ -1661,6 +1700,10 @@ static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) {
|
|||
if (!x)
|
||||
return -ENOMEM;
|
||||
|
||||
r = make_tmp_prefix(prefix);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
RUN_WITH_UMASK(0077)
|
||||
if (!mkdtemp(x))
|
||||
return -errno;
|
||||
|
|
|
@ -126,7 +126,15 @@ static int generate_wants_symlinks(void) {
|
|||
|
||||
STRV_FOREACH(u, arg_wants) {
|
||||
_cleanup_free_ char *p = NULL, *f = NULL;
|
||||
const char *target = arg_default_unit ?: SPECIAL_DEFAULT_TARGET;
|
||||
const char *target;
|
||||
|
||||
/* This should match what do_queue_default_job() in core/main.c does. */
|
||||
if (arg_default_unit)
|
||||
target = arg_default_unit;
|
||||
else if (in_initrd())
|
||||
target = SPECIAL_INITRD_TARGET;
|
||||
else
|
||||
target = SPECIAL_DEFAULT_TARGET;
|
||||
|
||||
p = strjoin(arg_dest, "/", target, ".wants/", *u);
|
||||
if (!p)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "sd-event.h"
|
||||
#include "sd-journal.h"
|
||||
|
||||
#include "time-util.h"
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <sys/ioctl.h>
|
||||
|
||||
#include "sd-dhcp-server.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp-internal.h"
|
||||
|
@ -13,7 +14,6 @@
|
|||
#include "fd-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "io-util.h"
|
||||
#include "sd-id128.h"
|
||||
#include "siphash24.h"
|
||||
#include "string-util.h"
|
||||
#include "unaligned.h"
|
||||
|
|
|
@ -682,3 +682,14 @@ global:
|
|||
sd_bus_object_vtable_format;
|
||||
sd_event_source_disable_unref;
|
||||
} LIBSYSTEMD_241;
|
||||
|
||||
LIBSYSTEMD_245 {
|
||||
global:
|
||||
sd_event_add_child_pidfd;
|
||||
sd_event_source_get_child_pidfd;
|
||||
sd_event_source_get_child_pidfd_own;
|
||||
sd_event_source_set_child_pidfd_own;
|
||||
sd_event_source_get_child_process_own;
|
||||
sd_event_source_set_child_process_own;
|
||||
sd_event_source_send_child_signal;
|
||||
} LIBSYSTEMD_243;
|
||||
|
|
|
@ -102,7 +102,6 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
|
|||
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRODUCT_UUID, EOPNOTSUPP),
|
||||
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_SPEED_METER_INACTIVE, EOPNOTSUPP),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_UNMANAGED_INTERFACE, EOPNOTSUPP),
|
||||
|
||||
SD_BUS_ERROR_MAP_END
|
||||
|
|
|
@ -81,7 +81,6 @@
|
|||
|
||||
#define BUS_ERROR_NO_PRODUCT_UUID "org.freedesktop.hostname1.NoProductUUID"
|
||||
|
||||
#define BUS_ERROR_SPEED_METER_INACTIVE "org.freedesktop.network1.SpeedMeterInactive"
|
||||
#define BUS_ERROR_UNMANAGED_INTERFACE "org.freedesktop.network1.UnmanagedInterface"
|
||||
|
||||
BUS_ERROR_MAP_ELF_USE(bus_common_errors);
|
||||
|
|
|
@ -34,7 +34,7 @@ typedef enum EventSourceType {
|
|||
* we know how to dispatch it */
|
||||
typedef enum WakeupType {
|
||||
WAKEUP_NONE,
|
||||
WAKEUP_EVENT_SOURCE,
|
||||
WAKEUP_EVENT_SOURCE, /* either I/O or pidfd wakeup */
|
||||
WAKEUP_CLOCK_DATA,
|
||||
WAKEUP_SIGNAL_DATA,
|
||||
WAKEUP_INOTIFY_DATA,
|
||||
|
@ -96,6 +96,12 @@ struct sd_event_source {
|
|||
siginfo_t siginfo;
|
||||
pid_t pid;
|
||||
int options;
|
||||
int pidfd;
|
||||
bool registered:1; /* whether the pidfd is registered in the epoll */
|
||||
bool pidfd_owned:1; /* close pidfd when event source is freed */
|
||||
bool process_owned:1; /* kill+reap process when event source is freed */
|
||||
bool exited:1; /* true if process exited (i.e. if there's value in SIGKILLing it if we want to get rid of it) */
|
||||
bool waited:1; /* true if process was waited for (i.e. if there's value in waitid(P_PID)'ing it if we want to get rid of it) */
|
||||
} child;
|
||||
struct {
|
||||
sd_event_handler_t callback;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "sd-id128.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "env-util.h"
|
||||
#include "event-source.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
|
@ -28,6 +29,14 @@
|
|||
|
||||
#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
|
||||
|
||||
static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) {
|
||||
/* Returns true if this is a PID event source and can be implemented by watching EPOLLIN */
|
||||
return s &&
|
||||
s->type == SOURCE_CHILD &&
|
||||
s->child.pidfd >= 0 &&
|
||||
s->child.options == WEXITED;
|
||||
}
|
||||
|
||||
static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
|
||||
[SOURCE_IO] = "io",
|
||||
[SOURCE_TIME_REALTIME] = "realtime",
|
||||
|
@ -356,8 +365,6 @@ static bool event_pid_changed(sd_event *e) {
|
|||
}
|
||||
|
||||
static void source_io_unregister(sd_event_source *s) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(s->type == SOURCE_IO);
|
||||
|
||||
|
@ -367,8 +374,7 @@ static void source_io_unregister(sd_event_source *s) {
|
|||
if (!s->io.registered)
|
||||
return;
|
||||
|
||||
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL);
|
||||
if (r < 0)
|
||||
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0)
|
||||
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
|
||||
strna(s->description), event_source_type_to_string(s->type));
|
||||
|
||||
|
@ -404,6 +410,51 @@ static int source_io_register(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void source_child_pidfd_unregister(sd_event_source *s) {
|
||||
assert(s);
|
||||
assert(s->type == SOURCE_CHILD);
|
||||
|
||||
if (event_pid_changed(s->event))
|
||||
return;
|
||||
|
||||
if (!s->child.registered)
|
||||
return;
|
||||
|
||||
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: %m",
|
||||
strna(s->description), event_source_type_to_string(s->type));
|
||||
|
||||
s->child.registered = false;
|
||||
}
|
||||
|
||||
static int source_child_pidfd_register(sd_event_source *s, int enabled) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(s->type == SOURCE_CHILD);
|
||||
assert(enabled != SD_EVENT_OFF);
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
struct epoll_event ev;
|
||||
|
||||
ev = (struct epoll_event) {
|
||||
.events = EPOLLIN | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0),
|
||||
.data.ptr = s,
|
||||
};
|
||||
|
||||
if (s->child.registered)
|
||||
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->child.pidfd, &ev);
|
||||
else
|
||||
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->child.pidfd, &ev);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
s->child.registered = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static clockid_t event_source_type_to_clock(EventSourceType t) {
|
||||
|
||||
switch (t) {
|
||||
|
@ -614,9 +665,8 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig)
|
|||
|
||||
assert(e);
|
||||
|
||||
/* Rechecks if the specified signal is still something we are
|
||||
* interested in. If not, we'll unmask it, and possibly drop
|
||||
* the signalfd for it. */
|
||||
/* Rechecks if the specified signal is still something we are interested in. If not, we'll unmask it,
|
||||
* and possibly drop the signalfd for it. */
|
||||
|
||||
if (sig == SIGCHLD &&
|
||||
e->n_enabled_child_sources > 0)
|
||||
|
@ -707,9 +757,13 @@ static void source_disconnect(sd_event_source *s) {
|
|||
}
|
||||
|
||||
(void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid));
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
}
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
source_child_pidfd_unregister(s);
|
||||
else
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_DEFER:
|
||||
|
@ -790,6 +844,44 @@ static void source_free(sd_event_source *s) {
|
|||
if (s->type == SOURCE_IO && s->io.owned)
|
||||
s->io.fd = safe_close(s->io.fd);
|
||||
|
||||
if (s->type == SOURCE_CHILD) {
|
||||
/* Eventually the kernel will do this automatically for us, but for now let's emulate this (unreliably) in userspace. */
|
||||
|
||||
if (s->child.process_owned) {
|
||||
|
||||
if (!s->child.exited) {
|
||||
bool sent = false;
|
||||
|
||||
if (s->child.pidfd >= 0) {
|
||||
if (pidfd_send_signal(s->child.pidfd, SIGKILL, NULL, 0) < 0) {
|
||||
if (errno == ESRCH) /* Already dead */
|
||||
sent = true;
|
||||
else if (!ERRNO_IS_NOT_SUPPORTED(errno))
|
||||
log_debug_errno(errno, "Failed to kill process " PID_FMT " via pidfd_send_signal(), re-trying via kill(): %m",
|
||||
s->child.pid);
|
||||
} else
|
||||
sent = true;
|
||||
}
|
||||
|
||||
if (!sent)
|
||||
if (kill(s->child.pid, SIGKILL) < 0)
|
||||
if (errno != ESRCH) /* Already dead */
|
||||
log_debug_errno(errno, "Failed to kill process " PID_FMT " via kill(), ignoring: %m",
|
||||
s->child.pid);
|
||||
}
|
||||
|
||||
if (!s->child.waited) {
|
||||
siginfo_t si = {};
|
||||
|
||||
/* Reap the child if we can */
|
||||
(void) waitid(P_PID, s->child.pid, &si, WEXITED);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->child.pidfd_owned)
|
||||
s->child.pidfd = safe_close(s->child.pidfd);
|
||||
}
|
||||
|
||||
if (s->destroy_callback)
|
||||
s->destroy_callback(s->userdata);
|
||||
|
||||
|
@ -1073,7 +1165,6 @@ _public_ int sd_event_add_signal(
|
|||
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
struct signal_data *d;
|
||||
sigset_t ss;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
|
@ -1085,11 +1176,10 @@ _public_ int sd_event_add_signal(
|
|||
if (!callback)
|
||||
callback = signal_exit_callback;
|
||||
|
||||
r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
|
||||
if (r != 0)
|
||||
return -r;
|
||||
|
||||
if (!sigismember(&ss, sig))
|
||||
r = signal_is_blocked(sig);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EBUSY;
|
||||
|
||||
if (!e->signal_sources) {
|
||||
|
@ -1124,6 +1214,11 @@ _public_ int sd_event_add_signal(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool shall_use_pidfd(void) {
|
||||
/* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */
|
||||
return getenv_bool_secure("SYSTEMD_PIDFD") != 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_add_child(
|
||||
sd_event *e,
|
||||
sd_event_source **ret,
|
||||
|
@ -1144,6 +1239,20 @@ _public_ int sd_event_add_child(
|
|||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(!event_pid_changed(e), -ECHILD);
|
||||
|
||||
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
|
||||
* take effect.
|
||||
*
|
||||
* (As an optimization we only do this check on the first child event source created.) */
|
||||
r = signal_is_blocked(SIGCHLD);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
r = hashmap_ensure_allocated(&e->child_sources, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -1155,18 +1264,131 @@ _public_ int sd_event_add_child(
|
|||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
s->wakeup = WAKEUP_EVENT_SOURCE;
|
||||
s->child.pid = pid;
|
||||
s->child.options = options;
|
||||
s->child.callback = callback;
|
||||
s->userdata = userdata;
|
||||
s->enabled = SD_EVENT_ONESHOT;
|
||||
|
||||
/* We always take a pidfd here if we can, even if we wait for anything else than WEXITED, so that we
|
||||
* pin the PID, and make regular waitid() handling race-free. */
|
||||
|
||||
if (shall_use_pidfd()) {
|
||||
s->child.pidfd = pidfd_open(s->child.pid, 0);
|
||||
if (s->child.pidfd < 0) {
|
||||
/* Propagate errors unless the syscall is not supported or blocked */
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return -errno;
|
||||
} else
|
||||
s->child.pidfd_owned = true; /* If we allocate the pidfd we own it by default */
|
||||
} else
|
||||
s->child.pidfd = -1;
|
||||
|
||||
r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
e->n_enabled_child_sources++;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* We have a pidfd and we only want to watch for exit */
|
||||
|
||||
r = source_child_pidfd_register(s, s->enabled);
|
||||
if (r < 0) {
|
||||
e->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
/* We have no pidfd or we shall wait for some other event than WEXITED */
|
||||
|
||||
r = event_make_signal_data(e, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
e->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
|
||||
e->need_process_child = true;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
|
||||
TAKE_PTR(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_add_child_pidfd(
|
||||
sd_event *e,
|
||||
sd_event_source **ret,
|
||||
int pidfd,
|
||||
int options,
|
||||
sd_event_child_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
assert_return(e = event_resolve(e), -ENOPKG);
|
||||
assert_return(pidfd >= 0, -EBADF);
|
||||
assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
|
||||
assert_return(options != 0, -EINVAL);
|
||||
assert_return(callback, -EINVAL);
|
||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(!event_pid_changed(e), -ECHILD);
|
||||
|
||||
if (e->n_enabled_child_sources == 0) {
|
||||
r = signal_is_blocked(SIGCHLD);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
r = hashmap_ensure_allocated(&e->child_sources, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidfd_get_pid(pidfd, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (hashmap_contains(e->child_sources, PID_TO_PTR(pid)))
|
||||
return -EBUSY;
|
||||
|
||||
s = source_new(e, !ret, SOURCE_CHILD);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
s->wakeup = WAKEUP_EVENT_SOURCE;
|
||||
s->child.pidfd = pidfd;
|
||||
s->child.pid = pid;
|
||||
s->child.options = options;
|
||||
s->child.callback = callback;
|
||||
s->child.pidfd_owned = false; /* If we got the pidfd passed in we don't own it by default (similar to the IO fd case) */
|
||||
s->userdata = userdata;
|
||||
s->enabled = SD_EVENT_ONESHOT;
|
||||
|
||||
r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
e->n_enabled_child_sources++;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* We only want to watch for WEXITED */
|
||||
|
||||
r = source_child_pidfd_register(s, s->enabled);
|
||||
if (r < 0) {
|
||||
e->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
/* We shall wait for some other event than WEXITED */
|
||||
|
||||
r = event_make_signal_data(e, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
e->n_enabled_child_sources--;
|
||||
|
@ -1174,11 +1396,12 @@ _public_ int sd_event_add_child(
|
|||
}
|
||||
|
||||
e->need_process_child = true;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
||||
TAKE_PTR(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1765,7 +1988,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
|
|||
return r;
|
||||
}
|
||||
|
||||
epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL);
|
||||
(void) epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2026,7 +2249,11 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
|||
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);
|
||||
else
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_EXIT:
|
||||
|
@ -2100,6 +2327,18 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
|||
|
||||
s->enabled = m;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* yes, we have pidfd */
|
||||
|
||||
r = source_child_pidfd_register(s, s->enabled);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
s->event->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
/* no pidfd, or something other to watch for than WEXITED */
|
||||
|
||||
r = event_make_signal_data(s->event, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
|
@ -2107,6 +2346,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
|||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
@ -2228,6 +2468,98 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_child_pidfd(sd_event_source *s) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||
|
||||
if (s->child.pidfd < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return s->child.pidfd;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||
assert_return(SIGNAL_VALID(sig), -EINVAL);
|
||||
|
||||
/* If we already have seen indication the process exited refuse sending a signal early. This way we
|
||||
* can be sure we don't accidentally kill the wrong process on PID reuse when pidfds are not
|
||||
* available. */
|
||||
if (s->child.exited)
|
||||
return -ESRCH;
|
||||
|
||||
if (s->child.pidfd >= 0) {
|
||||
siginfo_t copy;
|
||||
|
||||
/* pidfd_send_signal() changes the siginfo_t argument. This is weird, let's hence copy the
|
||||
* structure here */
|
||||
if (si)
|
||||
copy = *si;
|
||||
|
||||
if (pidfd_send_signal(s->child.pidfd, sig, si ? © : NULL, 0) < 0) {
|
||||
/* Let's propagate the error only if the system call is not implemented or prohibited */
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return -errno;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Flags are only supported for pidfd_send_signal(), not for rt_sigqueueinfo(), hence let's refuse
|
||||
* this here. */
|
||||
if (flags != 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (si) {
|
||||
/* We use rt_sigqueueinfo() only if siginfo_t is specified. */
|
||||
siginfo_t copy = *si;
|
||||
|
||||
if (rt_sigqueueinfo(s->child.pid, sig, ©) < 0)
|
||||
return -errno;
|
||||
} else if (kill(s->child.pid, sig) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
|
||||
if (s->child.pidfd < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return s->child.pidfd_owned;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
|
||||
if (s->child.pidfd < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
s->child.pidfd_owned = own;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_child_process_own(sd_event_source *s) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
|
||||
return s->child.process_owned;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_set_child_process_own(sd_event_source *s, int own) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
|
||||
s->child.process_owned = own;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(mask, -EINVAL);
|
||||
|
@ -2538,6 +2870,12 @@ static int process_child(sd_event *e) {
|
|||
if (s->enabled == SD_EVENT_OFF)
|
||||
continue;
|
||||
|
||||
if (s->child.exited)
|
||||
continue;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */
|
||||
continue;
|
||||
|
||||
zero(s->child.siginfo);
|
||||
r = waitid(P_PID, s->child.pid, &s->child.siginfo,
|
||||
WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options);
|
||||
|
@ -2547,6 +2885,9 @@ static int process_child(sd_event *e) {
|
|||
if (s->child.siginfo.si_pid != 0) {
|
||||
bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED);
|
||||
|
||||
if (zombie)
|
||||
s->child.exited = true;
|
||||
|
||||
if (!zombie && (s->child.options & WEXITED)) {
|
||||
/* If the child isn't dead then let's
|
||||
* immediately remove the state change
|
||||
|
@ -2566,6 +2907,33 @@ static int process_child(sd_event *e) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
|
||||
assert(e);
|
||||
assert(s);
|
||||
assert(s->type == SOURCE_CHILD);
|
||||
|
||||
if (s->pending)
|
||||
return 0;
|
||||
|
||||
if (s->enabled == SD_EVENT_OFF)
|
||||
return 0;
|
||||
|
||||
if (!EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
return 0;
|
||||
|
||||
zero(s->child.siginfo);
|
||||
if (waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0)
|
||||
return -errno;
|
||||
|
||||
if (s->child.siginfo.si_pid == 0)
|
||||
return 0;
|
||||
|
||||
if (IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED))
|
||||
s->child.exited = true;
|
||||
|
||||
return source_set_pending(s, true);
|
||||
}
|
||||
|
||||
static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
|
||||
bool read_one = false;
|
||||
int r;
|
||||
|
@ -2850,8 +3218,10 @@ static int source_dispatch(sd_event_source *s) {
|
|||
r = s->child.callback(s, &s->child.siginfo, s->userdata);
|
||||
|
||||
/* Now, reap the PID for good. */
|
||||
if (zombie)
|
||||
if (zombie) {
|
||||
(void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED);
|
||||
s->child.waited = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -3052,6 +3422,11 @@ _public_ int sd_event_prepare(sd_event *e) {
|
|||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
|
||||
|
||||
/* Let's check that if we are a default event loop we are executed in the correct thread. We only do
|
||||
* this check here once, since gettid() is typically not cached, and thus want to minimize
|
||||
* syscalls */
|
||||
assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO);
|
||||
|
||||
if (e->exit_requested)
|
||||
goto pending;
|
||||
|
||||
|
@ -3147,12 +3522,33 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
|
|||
|
||||
switch (*t) {
|
||||
|
||||
case WAKEUP_EVENT_SOURCE:
|
||||
r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events);
|
||||
case WAKEUP_EVENT_SOURCE: {
|
||||
sd_event_source *s = ev_queue[i].data.ptr;
|
||||
|
||||
assert(s);
|
||||
|
||||
switch (s->type) {
|
||||
|
||||
case SOURCE_IO:
|
||||
r = process_io(e, s, ev_queue[i].events);
|
||||
break;
|
||||
|
||||
case SOURCE_CHILD:
|
||||
r = process_pidfd(e, s, ev_queue[i].events);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Unexpected event source type");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WAKEUP_CLOCK_DATA: {
|
||||
struct clock_data *d = ev_queue[i].data.ptr;
|
||||
|
||||
assert(d);
|
||||
|
||||
r = flush_timer(e, d->fd, ev_queue[i].events, &d->next);
|
||||
break;
|
||||
}
|
||||
|
@ -3476,7 +3872,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
|
|||
|
||||
} else {
|
||||
if (e->watchdog_fd >= 0) {
|
||||
epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL);
|
||||
(void) epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL);
|
||||
e->watchdog_fd = safe_close(e->watchdog_fd);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "fs-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
|
@ -62,6 +63,11 @@ static int child_handler(sd_event_source *s, const siginfo_t *si, void *userdata
|
|||
assert_se(s);
|
||||
assert_se(si);
|
||||
|
||||
assert_se(si->si_uid == getuid());
|
||||
assert_se(si->si_signo == SIGCHLD);
|
||||
assert_se(si->si_code == CLD_EXITED);
|
||||
assert_se(si->si_status == 78);
|
||||
|
||||
log_info("got child on %c", PTR_TO_INT(userdata));
|
||||
|
||||
assert_se(userdata == INT_TO_PTR('f'));
|
||||
|
@ -75,6 +81,7 @@ static int child_handler(sd_event_source *s, const siginfo_t *si, void *userdata
|
|||
static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||
sd_event_source *p = NULL;
|
||||
pid_t pid;
|
||||
siginfo_t plain_si;
|
||||
|
||||
assert_se(s);
|
||||
assert_se(si);
|
||||
|
@ -83,16 +90,41 @@ static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si,
|
|||
|
||||
assert_se(userdata == INT_TO_PTR('e'));
|
||||
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGUSR2, -1) >= 0);
|
||||
|
||||
pid = fork();
|
||||
assert_se(pid >= 0);
|
||||
|
||||
if (pid == 0)
|
||||
_exit(EXIT_SUCCESS);
|
||||
if (pid == 0) {
|
||||
sigset_t ss;
|
||||
|
||||
assert_se(sigemptyset(&ss) >= 0);
|
||||
assert_se(sigaddset(&ss, SIGUSR2) >= 0);
|
||||
|
||||
zero(plain_si);
|
||||
assert_se(sigwaitinfo(&ss, &plain_si) >= 0);
|
||||
|
||||
assert_se(plain_si.si_signo == SIGUSR2);
|
||||
assert_se(plain_si.si_value.sival_int == 4711);
|
||||
|
||||
_exit(78);
|
||||
}
|
||||
|
||||
assert_se(sd_event_add_child(sd_event_source_get_event(s), &p, pid, WEXITED, child_handler, INT_TO_PTR('f')) >= 0);
|
||||
assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
|
||||
assert_se(sd_event_source_set_child_process_own(p, true) >= 0);
|
||||
|
||||
/* We can't use structured initialization here, since the structure contains various unions and these
|
||||
* fields lie in overlapping (carefully aligned) unions that LLVM is allergic to allow assignments
|
||||
* to */
|
||||
zero(plain_si);
|
||||
plain_si.si_signo = SIGUSR2;
|
||||
plain_si.si_code = SI_QUEUE;
|
||||
plain_si.si_pid = getpid();
|
||||
plain_si.si_uid = getuid();
|
||||
plain_si.si_value.sival_int = 4711;
|
||||
|
||||
assert_se(sd_event_source_send_child_signal(p, SIGUSR2, &plain_si, 0) >= 0);
|
||||
|
||||
sd_event_source_unref(s);
|
||||
|
||||
|
@ -119,7 +151,7 @@ static int defer_handler(sd_event_source *s, void *userdata) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static bool do_quit = false;
|
||||
static bool do_quit;
|
||||
|
||||
static int time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
log_info("got timer on %c", PTR_TO_INT(userdata));
|
||||
|
@ -161,7 +193,7 @@ static int post_handler(sd_event_source *s, void *userdata) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
static void test_basic(void) {
|
||||
static void test_basic(bool with_pidfd) {
|
||||
sd_event *e = NULL;
|
||||
sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
|
||||
static const char ch = 'x';
|
||||
|
@ -169,6 +201,8 @@ static void test_basic(void) {
|
|||
uint64_t event_now;
|
||||
int64_t priority;
|
||||
|
||||
assert_se(setenv("SYSTEMD_PIDFD", yes_no(with_pidfd), 1) >= 0);
|
||||
|
||||
assert_se(pipe(a) >= 0);
|
||||
assert_se(pipe(b) >= 0);
|
||||
assert_se(pipe(d) >= 0);
|
||||
|
@ -201,6 +235,8 @@ static void test_basic(void) {
|
|||
|
||||
assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0);
|
||||
assert_se(sd_event_add_io(e, &y, b[0], EPOLLIN, io_handler, INT_TO_PTR('b')) >= 0);
|
||||
|
||||
do_quit = false;
|
||||
assert_se(sd_event_add_time(e, &z, CLOCK_MONOTONIC, 0, 0, time_handler, INT_TO_PTR('c')) >= 0);
|
||||
assert_se(sd_event_add_exit(e, &q, exit_handler, INT_TO_PTR('g')) >= 0);
|
||||
|
||||
|
@ -258,6 +294,8 @@ static void test_basic(void) {
|
|||
safe_close_pair(b);
|
||||
safe_close_pair(d);
|
||||
safe_close_pair(k);
|
||||
|
||||
assert_se(unsetenv("SYSTEMD_PIDFD") >= 0);
|
||||
}
|
||||
|
||||
static void test_sd_event_now(void) {
|
||||
|
@ -482,15 +520,89 @@ static void test_inotify(unsigned n_create_events) {
|
|||
sd_event_unref(e);
|
||||
}
|
||||
|
||||
static int pidfd_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
|
||||
assert_se(s);
|
||||
assert_se(si);
|
||||
|
||||
assert_se(si->si_uid == getuid());
|
||||
assert_se(si->si_signo == SIGCHLD);
|
||||
assert_se(si->si_code == CLD_EXITED);
|
||||
assert_se(si->si_status == 66);
|
||||
|
||||
log_info("got pidfd on %c", PTR_TO_INT(userdata));
|
||||
|
||||
assert_se(userdata == INT_TO_PTR('p'));
|
||||
|
||||
assert_se(sd_event_exit(sd_event_source_get_event(s), 0) >= 0);
|
||||
sd_event_source_unref(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_pidfd(void) {
|
||||
sd_event_source *s = NULL, *t = NULL;
|
||||
sd_event *e = NULL;
|
||||
int pidfd;
|
||||
pid_t pid, pid2;
|
||||
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
_exit(66);
|
||||
}
|
||||
|
||||
assert_se(pid > 1);
|
||||
|
||||
pidfd = pidfd_open(pid, 0);
|
||||
if (pidfd < 0) {
|
||||
/* No pidfd_open() supported or blocked? */
|
||||
assert_se(ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno));
|
||||
(void) wait_for_terminate(pid, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
pid2 = fork();
|
||||
if (pid2 == 0)
|
||||
freeze();
|
||||
|
||||
assert_se(pid > 2);
|
||||
|
||||
assert_se(sd_event_default(&e) >= 0);
|
||||
assert_se(sd_event_add_child_pidfd(e, &s, pidfd, WEXITED, pidfd_handler, INT_TO_PTR('p')) >= 0);
|
||||
assert_se(sd_event_source_set_child_pidfd_own(s, true) >= 0);
|
||||
|
||||
/* This one should never trigger, since our second child lives forever */
|
||||
assert_se(sd_event_add_child(e, &t, pid2, WEXITED, pidfd_handler, INT_TO_PTR('q')) >= 0);
|
||||
assert_se(sd_event_source_set_child_process_own(t, true) >= 0);
|
||||
|
||||
assert_se(sd_event_loop(e) >= 0);
|
||||
|
||||
/* Child should still be alive */
|
||||
assert_se(kill(pid2, 0) >= 0);
|
||||
|
||||
t = sd_event_source_unref(t);
|
||||
|
||||
/* Child should now be dead, since we dropped the ref */
|
||||
assert_se(kill(pid2, 0) < 0 && errno == ESRCH);
|
||||
|
||||
sd_event_unref(e);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_INFO);
|
||||
|
||||
test_basic();
|
||||
test_basic(true); /* test with pidfd */
|
||||
test_basic(false); /* test without pidfd */
|
||||
|
||||
test_sd_event_now();
|
||||
test_rtqueue();
|
||||
|
||||
test_inotify(100); /* should work without overflow */
|
||||
test_inotify(33000); /* should trigger a q overflow */
|
||||
|
||||
test_pidfd();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -575,7 +575,9 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t
|
|||
assert_return(data, -EINVAL);
|
||||
|
||||
assert(m->n_containers < RTNL_CONTAINER_DEPTH);
|
||||
assert(m->containers[m->n_containers].attributes);
|
||||
|
||||
if (!m->containers[m->n_containers].attributes)
|
||||
return -ENODATA;
|
||||
|
||||
if (type >= m->containers[m->n_containers].n_attributes)
|
||||
return -ENODATA;
|
||||
|
@ -1021,6 +1023,27 @@ int sd_netlink_message_get_errno(const sd_netlink_message *m) {
|
|||
return err->error;
|
||||
}
|
||||
|
||||
static int netlink_message_parse_error(sd_netlink_message *m) {
|
||||
struct nlmsgerr *err = NLMSG_DATA(m->hdr);
|
||||
size_t hlen = sizeof(struct nlmsgerr);
|
||||
|
||||
/* no TLVs, nothing to do here */
|
||||
if (!(m->hdr->nlmsg_flags & NLM_F_ACK_TLVS))
|
||||
return 0;
|
||||
|
||||
/* if NLM_F_CAPPED is set then the inner err msg was capped */
|
||||
if (!(m->hdr->nlmsg_flags & NLM_F_CAPPED))
|
||||
hlen += err->msg.nlmsg_len - sizeof(struct nlmsghdr);
|
||||
|
||||
if (m->hdr->nlmsg_len <= NLMSG_SPACE(hlen))
|
||||
return 0;
|
||||
|
||||
return netlink_container_parse(m,
|
||||
&m->containers[m->n_containers],
|
||||
(struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + hlen),
|
||||
NLMSG_PAYLOAD(m->hdr, hlen));
|
||||
}
|
||||
|
||||
int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) {
|
||||
const NLType *nl_type;
|
||||
uint16_t type;
|
||||
|
@ -1060,6 +1083,9 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) {
|
|||
|
||||
m->containers[0].type_system = type_system;
|
||||
|
||||
if (sd_netlink_message_is_error(m))
|
||||
r = netlink_message_parse_error(m);
|
||||
else
|
||||
r = netlink_container_parse(m,
|
||||
&m->containers[m->n_containers],
|
||||
(struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
|
||||
|
|
|
@ -745,9 +745,19 @@ static const NLTypeSystem rtnl_qdisc_type_system = {
|
|||
.types = rtnl_qdisc_types,
|
||||
};
|
||||
|
||||
static const NLType error_types[] = {
|
||||
[NLMSGERR_ATTR_MSG] = { .type = NETLINK_TYPE_STRING },
|
||||
[NLMSGERR_ATTR_OFFS] = { .type = NETLINK_TYPE_U32 },
|
||||
};
|
||||
|
||||
static const NLTypeSystem error_type_system = {
|
||||
.count = ELEMENTSOF(error_types),
|
||||
.types = error_types,
|
||||
};
|
||||
|
||||
static const NLType rtnl_types[] = {
|
||||
[NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
|
||||
[NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
|
||||
[NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) },
|
||||
[RTM_NEWLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
|
||||
[RTM_DELLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
|
||||
[RTM_GETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
|
||||
|
@ -1052,7 +1062,7 @@ const NLTypeSystem genl_family_type_system_root = {
|
|||
};
|
||||
|
||||
static const NLType genl_types[] = {
|
||||
[SD_GENL_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
|
||||
[SD_GENL_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) },
|
||||
[SD_GENL_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system },
|
||||
[SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) },
|
||||
[SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system, .size = sizeof(struct genlmsghdr) },
|
||||
|
|
|
@ -107,6 +107,10 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
|
|||
rtnl->fd = fd;
|
||||
rtnl->protocol = protocol;
|
||||
|
||||
r = setsockopt_int(fd, SOL_NETLINK, NETLINK_EXT_ACK, 1);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "sd-netlink: Failed to enable NETLINK_EXT_ACK option, ignoring: %m");
|
||||
|
||||
r = socket_bind(rtnl);
|
||||
if (r < 0) {
|
||||
rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
|
||||
|
|
|
@ -587,7 +587,7 @@ const NetDevVTable bond_vtable = {
|
|||
.object_size = sizeof(Bond),
|
||||
.init = bond_init,
|
||||
.done = bond_done,
|
||||
.sections = "Match\0NetDev\0Bond\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Bond\0",
|
||||
.fill_message_create = netdev_bond_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_MASTER,
|
||||
.generate_mac = true,
|
||||
|
|
|
@ -355,7 +355,7 @@ static void bridge_init(NetDev *n) {
|
|||
const NetDevVTable bridge_vtable = {
|
||||
.object_size = sizeof(Bridge),
|
||||
.init = bridge_init,
|
||||
.sections = "Match\0NetDev\0Bridge\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Bridge\0",
|
||||
.post_create = netdev_bridge_post_create,
|
||||
.create_type = NETDEV_CREATE_MASTER,
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
const NetDevVTable dummy_vtable = {
|
||||
.object_size = sizeof(Dummy),
|
||||
.sections = "Match\0NetDev\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.generate_mac = true,
|
||||
};
|
||||
|
|
|
@ -262,7 +262,7 @@ static void fou_tunnel_init(NetDev *netdev) {
|
|||
const NetDevVTable foutnl_vtable = {
|
||||
.object_size = sizeof(FouTunnel),
|
||||
.init = fou_tunnel_init,
|
||||
.sections = "Match\0NetDev\0FooOverUDP\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "FooOverUDP\0",
|
||||
.create = netdev_fou_tunnel_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.config_verify = netdev_fou_tunnel_verify,
|
||||
|
|
|
@ -348,7 +348,7 @@ static void geneve_init(NetDev *netdev) {
|
|||
const NetDevVTable geneve_vtable = {
|
||||
.object_size = sizeof(Geneve),
|
||||
.init = geneve_init,
|
||||
.sections = "Match\0NetDev\0GENEVE\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "GENEVE\0",
|
||||
.create = netdev_geneve_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.config_verify = netdev_geneve_verify,
|
||||
|
|
|
@ -74,7 +74,7 @@ static void ipvlan_init(NetDev *n) {
|
|||
const NetDevVTable ipvlan_vtable = {
|
||||
.object_size = sizeof(IPVlan),
|
||||
.init = ipvlan_init,
|
||||
.sections = "Match\0NetDev\0IPVLAN\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "IPVLAN\0",
|
||||
.fill_message_create = netdev_ipvlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.generate_mac = true,
|
||||
|
@ -83,7 +83,7 @@ const NetDevVTable ipvlan_vtable = {
|
|||
const NetDevVTable ipvtap_vtable = {
|
||||
.object_size = sizeof(IPVlan),
|
||||
.init = ipvlan_init,
|
||||
.sections = "Match\0NetDev\0IPVTAP\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "IPVTAP\0",
|
||||
.fill_message_create = netdev_ipvlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.generate_mac = true,
|
||||
|
|
|
@ -723,7 +723,7 @@ static void l2tp_tunnel_done(NetDev *netdev) {
|
|||
const NetDevVTable l2tptnl_vtable = {
|
||||
.object_size = sizeof(L2tpTunnel),
|
||||
.init = l2tp_tunnel_init,
|
||||
.sections = "Match\0NetDev\0L2TP\0L2TPSession\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "L2TP\0L2TPSession\0",
|
||||
.create_after_configured = l2tp_create_tunnel,
|
||||
.done = l2tp_tunnel_done,
|
||||
.create_type = NETDEV_CREATE_AFTER_CONFIGURED,
|
||||
|
|
|
@ -1235,7 +1235,7 @@ static void macsec_done(NetDev *netdev) {
|
|||
const NetDevVTable macsec_vtable = {
|
||||
.object_size = sizeof(MACsec),
|
||||
.init = macsec_init,
|
||||
.sections = "Match\0NetDev\0MACsec\0MACsecReceiveChannel\0MACsecTransmitAssociation\0MACsecReceiveAssociation\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "MACsec\0MACsecReceiveChannel\0MACsecTransmitAssociation\0MACsecReceiveAssociation\0",
|
||||
.fill_message_create = netdev_macsec_fill_message_create,
|
||||
.post_create = netdev_macsec_configure,
|
||||
.done = macsec_done,
|
||||
|
|
|
@ -58,7 +58,7 @@ static void macvlan_init(NetDev *n) {
|
|||
const NetDevVTable macvtap_vtable = {
|
||||
.object_size = sizeof(MacVlan),
|
||||
.init = macvlan_init,
|
||||
.sections = "Match\0NetDev\0MACVTAP\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "MACVTAP\0",
|
||||
.fill_message_create = netdev_macvlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.generate_mac = true,
|
||||
|
@ -67,7 +67,7 @@ const NetDevVTable macvtap_vtable = {
|
|||
const NetDevVTable macvlan_vtable = {
|
||||
.object_size = sizeof(MacVlan),
|
||||
.init = macvlan_init,
|
||||
.sections = "Match\0NetDev\0MACVLAN\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "MACVLAN\0",
|
||||
.fill_message_create = netdev_macvlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.generate_mac = true,
|
||||
|
|
|
@ -682,9 +682,9 @@ int netdev_load_one(Manager *manager, const char *filename) {
|
|||
|
||||
dropin_dirname = strjoina(basename(filename), ".d");
|
||||
r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
|
||||
"Match\0NetDev\0",
|
||||
NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS,
|
||||
config_item_perf_lookup, network_netdev_gperf_lookup,
|
||||
CONFIG_PARSE_WARN|CONFIG_PARSE_RELAXED, netdev_raw);
|
||||
CONFIG_PARSE_WARN, netdev_raw);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -8,6 +8,35 @@
|
|||
#include "networkd-link.h"
|
||||
#include "time-util.h"
|
||||
|
||||
#define NETDEV_COMMON_SECTIONS "Match\0NetDev\0"
|
||||
/* This is the list of known sections. We need to ignore them in the initial parsing phase. */
|
||||
#define NETDEV_OTHER_SECTIONS \
|
||||
"-Bond\0" \
|
||||
"-Bridge\0" \
|
||||
"-FooOverUDP\0" \
|
||||
"-GENEVE\0" \
|
||||
"-IPVLAN\0" \
|
||||
"-IPVTAP\0" \
|
||||
"-L2TP\0" \
|
||||
"-L2TPSession\0" \
|
||||
"-MACsec\0" \
|
||||
"-MACsecReceiveChannel\0" \
|
||||
"-MACsecTransmitAssociation\0" \
|
||||
"-MACsecReceiveAssociation\0" \
|
||||
"-MACVTAP\0" \
|
||||
"-MACVLAN\0" \
|
||||
"-Tunnel\0" \
|
||||
"-Tun\0" \
|
||||
"-Tap\0" \
|
||||
"-Peer\0" \
|
||||
"-VLAN\0" \
|
||||
"-VRF\0" \
|
||||
"-VXCAN\0" \
|
||||
"-VXLAN\0" \
|
||||
"-WireGuard\0" \
|
||||
"-WireGuardPeer\0" \
|
||||
"-Xfrm\0"
|
||||
|
||||
typedef struct netdev_join_callback netdev_join_callback;
|
||||
|
||||
struct netdev_join_callback {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
const NetDevVTable netdevsim_vtable = {
|
||||
.object_size = sizeof(NetDevSim),
|
||||
.sections = "Match\0NetDev\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.generate_mac = true,
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ static int netdev_nlmon_verify(NetDev *netdev, const char *filename) {
|
|||
|
||||
const NetDevVTable nlmon_vtable = {
|
||||
.object_size = sizeof(NLMon),
|
||||
.sections = "Match\0NetDev\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.config_verify = netdev_nlmon_verify,
|
||||
};
|
||||
|
|
|
@ -805,7 +805,7 @@ static void ip6tnl_init(NetDev *n) {
|
|||
const NetDevVTable ipip_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = ipip_sit_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||
.fill_message_create = netdev_ipip_sit_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
|
@ -815,7 +815,7 @@ const NetDevVTable ipip_vtable = {
|
|||
const NetDevVTable sit_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = ipip_sit_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||
.fill_message_create = netdev_ipip_sit_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
|
@ -825,7 +825,7 @@ const NetDevVTable sit_vtable = {
|
|||
const NetDevVTable vti_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = vti_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||
.fill_message_create = netdev_vti_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
|
@ -835,7 +835,7 @@ const NetDevVTable vti_vtable = {
|
|||
const NetDevVTable vti6_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = vti_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||
.fill_message_create = netdev_vti_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
|
@ -845,7 +845,7 @@ const NetDevVTable vti6_vtable = {
|
|||
const NetDevVTable gre_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = gre_erspan_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||
.fill_message_create = netdev_gre_erspan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
|
@ -855,7 +855,7 @@ const NetDevVTable gre_vtable = {
|
|||
const NetDevVTable gretap_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = gre_erspan_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||
.fill_message_create = netdev_gre_erspan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
|
@ -865,7 +865,7 @@ const NetDevVTable gretap_vtable = {
|
|||
const NetDevVTable ip6gre_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = ip6gre_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||
.fill_message_create = netdev_ip6gre_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
|
@ -875,7 +875,7 @@ const NetDevVTable ip6gre_vtable = {
|
|||
const NetDevVTable ip6gretap_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = ip6gre_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||
.fill_message_create = netdev_ip6gre_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
|
@ -885,7 +885,7 @@ const NetDevVTable ip6gretap_vtable = {
|
|||
const NetDevVTable ip6tnl_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = ip6tnl_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||
.fill_message_create = netdev_ip6tnl_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
|
@ -895,7 +895,7 @@ const NetDevVTable ip6tnl_vtable = {
|
|||
const NetDevVTable erspan_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = gre_erspan_init,
|
||||
.sections = "Match\0NetDev\0Tunnel\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||
.fill_message_create = netdev_gre_erspan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
|
|
|
@ -147,7 +147,7 @@ static int tuntap_verify(NetDev *netdev, const char *filename) {
|
|||
|
||||
const NetDevVTable tun_vtable = {
|
||||
.object_size = sizeof(TunTap),
|
||||
.sections = "Match\0NetDev\0Tun\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tun\0",
|
||||
.config_verify = tuntap_verify,
|
||||
.done = tuntap_done,
|
||||
.create = netdev_create_tuntap,
|
||||
|
@ -156,7 +156,7 @@ const NetDevVTable tun_vtable = {
|
|||
|
||||
const NetDevVTable tap_vtable = {
|
||||
.object_size = sizeof(TunTap),
|
||||
.sections = "Match\0NetDev\0Tap\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tap\0",
|
||||
.config_verify = tuntap_verify,
|
||||
.done = tuntap_done,
|
||||
.create = netdev_create_tuntap,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
const NetDevVTable vcan_vtable = {
|
||||
.object_size = sizeof(VCan),
|
||||
.sections = "Match\0NetDev\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.generate_mac = true,
|
||||
};
|
||||
|
|
|
@ -85,7 +85,7 @@ static void veth_done(NetDev *n) {
|
|||
|
||||
const NetDevVTable veth_vtable = {
|
||||
.object_size = sizeof(Veth),
|
||||
.sections = "Match\0NetDev\0Peer\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Peer\0",
|
||||
.done = veth_done,
|
||||
.fill_message_create = netdev_veth_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
|
|
|
@ -85,7 +85,7 @@ static void vlan_init(NetDev *netdev) {
|
|||
const NetDevVTable vlan_vtable = {
|
||||
.object_size = sizeof(VLan),
|
||||
.init = vlan_init,
|
||||
.sections = "Match\0NetDev\0VLAN\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "VLAN\0",
|
||||
.fill_message_create = netdev_vlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_vlan_verify,
|
||||
|
|
|
@ -25,7 +25,7 @@ static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink
|
|||
|
||||
const NetDevVTable vrf_vtable = {
|
||||
.object_size = sizeof(Vrf),
|
||||
.sections = "Match\0NetDev\0VRF\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "VRF\0",
|
||||
.fill_message_create = netdev_vrf_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_MASTER,
|
||||
.generate_mac = true,
|
||||
|
|
|
@ -65,7 +65,7 @@ static void vxcan_done(NetDev *n) {
|
|||
|
||||
const NetDevVTable vxcan_vtable = {
|
||||
.object_size = sizeof(VxCan),
|
||||
.sections = "Match\0NetDev\0VXCAN\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "VXCAN\0",
|
||||
.done = vxcan_done,
|
||||
.fill_message_create = netdev_vxcan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
|
|
|
@ -371,7 +371,7 @@ static void vxlan_init(NetDev *netdev) {
|
|||
const NetDevVTable vxlan_vtable = {
|
||||
.object_size = sizeof(VxLan),
|
||||
.init = vxlan_init,
|
||||
.sections = "Match\0NetDev\0VXLAN\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "VXLAN\0",
|
||||
.fill_message_create = netdev_vxlan_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.config_verify = netdev_vxlan_verify,
|
||||
|
|
|
@ -967,7 +967,7 @@ static int wireguard_verify(NetDev *netdev, const char *filename) {
|
|||
|
||||
const NetDevVTable wireguard_vtable = {
|
||||
.object_size = sizeof(Wireguard),
|
||||
.sections = "Match\0NetDev\0WireGuard\0WireGuardPeer\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "WireGuard\0WireGuardPeer\0",
|
||||
.post_create = netdev_wireguard_post_create,
|
||||
.init = wireguard_init,
|
||||
.done = wireguard_done,
|
||||
|
|
|
@ -27,7 +27,7 @@ static int xfrm_fill_message_create(NetDev *netdev, Link *link, sd_netlink_messa
|
|||
|
||||
const NetDevVTable xfrm_vtable = {
|
||||
.object_size = sizeof(Xfrm),
|
||||
.sections = "Match\0NetDev\0Xfrm\0",
|
||||
.sections = NETDEV_COMMON_SECTIONS "Xfrm\0",
|
||||
.fill_message_create = xfrm_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_STACKED
|
||||
};
|
||||
|
|
|
@ -349,8 +349,7 @@ static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
|
|||
"org.freedesktop.network1.Link",
|
||||
"BitRates");
|
||||
if (r < 0) {
|
||||
bool quiet = sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY) ||
|
||||
sd_bus_error_has_name(&error, BUS_ERROR_SPEED_METER_INACTIVE);
|
||||
bool quiet = sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY);
|
||||
|
||||
return log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING,
|
||||
r, "Failed to query link bit rates: %s", bus_error_message(&error, r));
|
||||
|
@ -368,7 +367,7 @@ static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
|
|||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
link->has_bitrates = true;
|
||||
link->has_bitrates = link->tx_bitrate != UINT64_MAX && link->rx_bitrate != UINT64_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_warning_errno(link, r, "could not set address label: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set address label");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
} else if (r >= 0)
|
||||
|
|
|
@ -431,7 +431,7 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EADDRNOTAVAIL)
|
||||
log_link_warning_errno(link, r, "Could not drop address: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not drop address");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *lin
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
log_link_error_errno(link, r, "Could not add VLAN to bridge port: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not add VLAN to bridge port");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
/* we warn but don't fail the link, as it may be brought up later */
|
||||
log_link_warning_errno(link, r, "Could not bring up interface: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not bring up interface");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_error_errno(link, r, "Failed to configure CAN link: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Failed to configure CAN link");
|
||||
link_enter_failed(link);
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Could not bring down interface: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not bring down interface");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -65,11 +65,11 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
|
|||
/* It seems kernel does not support that the prefix route cannot be configured with
|
||||
* route table. Let's once drop the config and reconfigure them later. */
|
||||
|
||||
log_link_debug_errno(link, r, "Could not set DHCPv4 route, retrying later: %m");
|
||||
log_link_message_debug_errno(link, m, r, "Could not set DHCPv4 route, retrying later: %m");
|
||||
link->dhcp4_route_failed = true;
|
||||
link->manager->dhcp4_prefix_root_cannot_set_table = true;
|
||||
} else if (r < 0 && r != -EEXIST) {
|
||||
log_link_error_errno(link, r, "Could not set DHCPv4 route: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set DHCPv4 route: %m");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
@ -543,7 +543,7 @@ static int dhcp_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_debug_errno(link, r, "Failed to remove DHCPv4 address, ignoring: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 address, ignoring");
|
||||
else
|
||||
(void) manager_rtnl_process_address(rtnl, m, link->manager);
|
||||
|
||||
|
@ -665,7 +665,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set DHCPv4 address");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
} else if (r >= 0)
|
||||
|
|
|
@ -112,7 +112,7 @@ static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Lin
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_debug_errno(link, r, "Received error on unreachable route removal for DHCPv6 delegated subnet: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Received error on unreachable route removal for DHCPv6 delegated subnet");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
log_link_debug_errno(link, r, "Received error when adding unreachable route for DHCPv6 delegated subnet: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Received error when adding unreachable route for DHCPv6 delegated subnet");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -402,7 +402,7 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_error_errno(link, r, "Could not set DHCPv6 address: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set DHCPv6 address");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
} else if (r >= 0)
|
||||
|
@ -714,7 +714,7 @@ static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, Link *
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_debug_errno(link, r, "Received error adding DHCPv6 Prefix Delegation route: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Received error adding DHCPv6 Prefix Delegation route");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
@ -780,7 +780,7 @@ static int dhcp6_prefix_remove_handler(sd_netlink *nl, sd_netlink_message *m, Li
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Received error on DHCPv6 Prefix Delegation route removal: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Received error on DHCPv6 Prefix Delegation route removal");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_error_errno(link, r, "Could not add FDB entry: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not add FDB entry");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_error_errno(link, r, "could not set ipv4ll address: %m");
|
||||
log_link_message_warning_errno(link, m, r, "could not set ipv4ll address");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
} else if (r >= 0)
|
||||
|
|
|
@ -141,7 +141,7 @@ static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_messa
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
log_link_error_errno(link, r, "Could not add IPv6 proxy ndp address entry: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not add IPv6 proxy ndp address entry, ignoring");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -41,14 +41,10 @@ static int property_get_bit_rates(
|
|||
|
||||
manager = link->manager;
|
||||
|
||||
if (!manager->use_speed_meter)
|
||||
return sd_bus_error_set(error, BUS_ERROR_SPEED_METER_INACTIVE, "Speed meter is disabled.");
|
||||
|
||||
if (manager->speed_meter_usec_old == 0)
|
||||
return sd_bus_error_set(error, BUS_ERROR_SPEED_METER_INACTIVE, "Speed meter is not active.");
|
||||
|
||||
if (!link->stats_updated)
|
||||
return sd_bus_error_set(error, BUS_ERROR_SPEED_METER_INACTIVE, "Failed to measure bit-rates.");
|
||||
if (!manager->use_speed_meter ||
|
||||
manager->speed_meter_usec_old == 0 ||
|
||||
!link->stats_updated)
|
||||
return sd_bus_message_append(reply, "(tt)", UINT64_MAX, UINT64_MAX);
|
||||
|
||||
assert(manager->speed_meter_usec_new > manager->speed_meter_usec_old);
|
||||
interval_sec = (manager->speed_meter_usec_new - manager->speed_meter_usec_old) / USEC_PER_SEC;
|
||||
|
|
|
@ -929,7 +929,7 @@ static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_warning_errno(link, r, "Could not set nexthop: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set nexthop");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
@ -981,7 +981,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_warning_errno(link, r, "Could not set route: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set route");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1170,7 +1170,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_warning_errno(link, r, "could not set address: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set address");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
} else if (r >= 0)
|
||||
|
@ -1303,7 +1303,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not set MTU, ignoring: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set MTU, ignoring");
|
||||
else
|
||||
log_link_debug(link, "Setting MTU done.");
|
||||
|
||||
|
@ -1415,7 +1415,7 @@ static int set_flags_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not set link flags, ignoring: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set link flags, ignoring");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1582,7 +1582,7 @@ static int link_address_genmode_handler(sd_netlink *rtnl, sd_netlink_message *m,
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not set address genmode for interface, ignoring: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set address genmode for interface, ignoring");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1656,7 +1656,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
/* we warn but don't fail the link, as it may be brought up later */
|
||||
log_link_warning_errno(link, r, "Could not bring up interface: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not bring up interface");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1713,7 +1713,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not bring down interface: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not bring down interface");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -2118,7 +2118,7 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_error_errno(link, r, "Could not join netdev: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not join netdev");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
@ -4053,3 +4053,10 @@ static const char* const link_state_table[_LINK_STATE_MAX] = {
|
|||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
|
||||
|
||||
int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg) {
|
||||
const char *err_msg = NULL;
|
||||
|
||||
(void) sd_netlink_message_read_string(m, NLMSGERR_ATTR_MSG, &err_msg);
|
||||
return log_link_full(link, level, err, "%s: %s%s%m", msg, strempty(err_msg), err_msg ? " " : "");
|
||||
}
|
||||
|
|
|
@ -213,6 +213,13 @@ int link_request_set_nexthop(Link *link);
|
|||
|
||||
int link_reconfigure(Link *link, bool force);
|
||||
|
||||
int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg);
|
||||
#define log_link_message_error_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_ERR, err, msg)
|
||||
#define log_link_message_warning_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_WARNING, err, msg)
|
||||
#define log_link_message_notice_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_NOTICE, err, msg)
|
||||
#define log_link_message_info_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_INFO, err, msg)
|
||||
#define log_link_message_debug_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_DEBUG, err, msg)
|
||||
|
||||
#define ADDRESS_FMT_VAL(address) \
|
||||
be32toh((address).s_addr) >> 24, \
|
||||
(be32toh((address).s_addr) >> 16) & 0xFFu, \
|
||||
|
|
|
@ -41,6 +41,13 @@
|
|||
/* use 8 MB for receive socket kernel queue. */
|
||||
#define RCVBUF_SIZE (8*1024*1024)
|
||||
|
||||
static int log_message_warning_errno(sd_netlink_message *m, int err, const char *msg) {
|
||||
const char *err_msg = NULL;
|
||||
|
||||
(void) sd_netlink_message_read_string(m, NLMSGERR_ATTR_MSG, &err_msg);
|
||||
return log_warning_errno(err, "%s: %s%s%m", msg, strempty(err_msg), err_msg ? " " : "");
|
||||
}
|
||||
|
||||
static int setup_default_address_pool(Manager *m) {
|
||||
AddressPool *p;
|
||||
int r;
|
||||
|
@ -283,7 +290,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
|
|||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to receive route message, ignoring: %m");
|
||||
log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -576,7 +583,7 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to receive neighbor message, ignoring: %m");
|
||||
log_message_warning_errno(message, r, "rtnl: failed to receive neighbor message, ignoring");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -714,7 +721,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to receive address message, ignoring: %m");
|
||||
log_message_warning_errno(message, r, "rtnl: failed to receive address message, ignoring");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -867,7 +874,7 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa
|
|||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: Could not receive link message, ignoring: %m");
|
||||
log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -957,7 +964,7 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
|
|||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to receive rule message, ignoring: %m");
|
||||
log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1170,7 +1177,7 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "rtnl: failed to receive rule message, ignoring: %m");
|
||||
log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ static int ndisc_netlink_route_message_handler(sd_netlink *rtnl, sd_netlink_mess
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
|
||||
log_link_message_error_errno(link, m, r, "Could not set NDisc route or address");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ static int ndisc_netlink_address_message_handler(sd_netlink *rtnl, sd_netlink_me
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
|
||||
log_link_message_error_errno(link, m, r, "Could not set NDisc route or address");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
} else if (r >= 0)
|
||||
|
|
|
@ -102,7 +102,7 @@ static int neighbor_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, L
|
|||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
/* Neighbor may not exist yet. So, do not enter failed state here. */
|
||||
log_link_warning_errno(link, r, "Could not set neighbor, ignoring: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not set neighbor, ignoring");
|
||||
|
||||
if (link->neighbor_messages == 0) {
|
||||
log_link_debug(link, "Neighbors set");
|
||||
|
@ -171,7 +171,7 @@ static int neighbor_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
|
|||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -ESRCH)
|
||||
/* Neighbor may not exist because it already got deleted, ignore that. */
|
||||
log_link_warning_errno(link, r, "Could not remove neighbor: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not remove neighbor");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -278,7 +278,7 @@ static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -ESRCH)
|
||||
log_link_warning_errno(link, r, "Could not drop nexthop: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not drop nexthop, ignoring");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -398,7 +398,7 @@ static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *l
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -ESRCH)
|
||||
log_link_warning_errno(link, r, "Could not drop route: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not drop route, ignoring");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -317,7 +317,7 @@ static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_messa
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not drop routing policy rule: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not drop routing policy rule");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -431,7 +431,7 @@ static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m,
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
|
||||
log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
|||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_error_errno(link, r, "Could not set QDisc: %m");
|
||||
log_link_message_error_errno(link, m, r, "Could not set QDisc: %m");
|
||||
link_enter_failed(link);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,8 @@ systemd_resolved_sources = files('''
|
|||
resolved-etc-hosts.h
|
||||
resolved-etc-hosts.c
|
||||
resolved-dnstls.h
|
||||
resolved-util.c
|
||||
resolved-util.h
|
||||
'''.split())
|
||||
|
||||
resolvectl_sources = files('''
|
||||
|
@ -228,4 +230,10 @@ tests += [
|
|||
[],
|
||||
[],
|
||||
'ENABLE_RESOLVE', 'manual'],
|
||||
|
||||
[['src/resolve/test-resolved-util.c',
|
||||
'src/resolve/resolved-util.c',
|
||||
'src/resolve/resolved-util.h'],
|
||||
[],
|
||||
[]],
|
||||
]
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "parse-util.h"
|
||||
#include "resolved-conf.h"
|
||||
#include "resolved-dnssd.h"
|
||||
#include "resolved-util.h"
|
||||
#include "specifier.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
|
@ -27,11 +28,12 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
|
|||
union in_addr_union address;
|
||||
int family, r, ifindex = 0;
|
||||
DnsServer *s;
|
||||
_cleanup_free_ char *server_name = NULL;
|
||||
|
||||
assert(m);
|
||||
assert(word);
|
||||
|
||||
r = in_addr_ifindex_from_string_auto(word, &family, &address, &ifindex);
|
||||
r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -52,7 +54,7 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
|
|||
return 0;
|
||||
}
|
||||
|
||||
return dns_server_new(m, NULL, type, NULL, family, &address, ifindex);
|
||||
return dns_server_new(m, NULL, type, NULL, family, &address, ifindex, server_name);
|
||||
}
|
||||
|
||||
int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
|
||||
|
|
|
@ -25,8 +25,10 @@ int dns_server_new(
|
|||
Link *l,
|
||||
int family,
|
||||
const union in_addr_union *in_addr,
|
||||
int ifindex) {
|
||||
int ifindex,
|
||||
const char *server_name) {
|
||||
|
||||
_cleanup_free_ char *name = NULL;
|
||||
DnsServer *s;
|
||||
|
||||
assert(m);
|
||||
|
@ -44,6 +46,12 @@ int dns_server_new(
|
|||
return -E2BIG;
|
||||
}
|
||||
|
||||
if (server_name) {
|
||||
name = strdup(server_name);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
s = new(DnsServer, 1);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
@ -55,6 +63,7 @@ int dns_server_new(
|
|||
.family = family,
|
||||
.address = *in_addr,
|
||||
.ifindex = ifindex,
|
||||
.server_name = TAKE_PTR(name),
|
||||
};
|
||||
|
||||
dns_server_reset_features(s);
|
||||
|
@ -107,6 +116,7 @@ static DnsServer* dns_server_free(DnsServer *s) {
|
|||
#endif
|
||||
|
||||
free(s->server_string);
|
||||
free(s->server_name);
|
||||
return mfree(s);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ struct DnsServer {
|
|||
|
||||
char *server_string;
|
||||
|
||||
char *server_name;
|
||||
|
||||
/* The long-lived stream towards this server. */
|
||||
DnsStream *stream;
|
||||
|
||||
|
@ -94,7 +96,8 @@ int dns_server_new(
|
|||
Link *link,
|
||||
int family,
|
||||
const union in_addr_union *address,
|
||||
int ifindex);
|
||||
int ifindex,
|
||||
const char *server_string);
|
||||
|
||||
DnsServer* dns_server_ref(DnsServer *s);
|
||||
DnsServer* dns_server_unref(DnsServer *s);
|
||||
|
|
|
@ -67,6 +67,12 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
|
|||
gnutls_session_set_verify_cert2(gs, &stream->dnstls_data.validation, 1, 0);
|
||||
}
|
||||
|
||||
if (server->server_name) {
|
||||
r = gnutls_server_name_set(gs, GNUTLS_NAME_DNS, server->server_name, strlen(server->server_name));
|
||||
if (r < 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", gnutls_strerror(r));
|
||||
}
|
||||
|
||||
gnutls_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
|
||||
|
||||
gnutls_transport_set_ptr2(gs, (gnutls_transport_ptr_t) (long) stream->fd, stream);
|
||||
|
|
|
@ -87,6 +87,17 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
|
|||
return -ECONNREFUSED;
|
||||
}
|
||||
|
||||
if (server->server_name) {
|
||||
r = SSL_set_tlsext_host_name(s, server->server_name);
|
||||
if (r <= 0) {
|
||||
char errbuf[256];
|
||||
|
||||
error = ERR_get_error();
|
||||
ERR_error_string_n(error, errbuf, sizeof(errbuf));
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", errbuf);
|
||||
}
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
stream->dnstls_data.handshake = SSL_do_handshake(s);
|
||||
if (stream->dnstls_data.handshake <= 0) {
|
||||
|
|
|
@ -284,7 +284,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
|
|||
if (s)
|
||||
dns_server_move_back_and_unmark(s);
|
||||
else {
|
||||
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0);
|
||||
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0, NULL);
|
||||
if (r < 0)
|
||||
goto clear;
|
||||
}
|
||||
|
|
|
@ -269,7 +269,7 @@ static int link_update_dns_server_one(Link *l, const char *name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0);
|
||||
return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0, NULL);
|
||||
}
|
||||
|
||||
static int link_update_dns_servers(Link *l) {
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "macro.h"
|
||||
#include "resolved-util.h"
|
||||
|
||||
int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
|
||||
_cleanup_free_ char *buf = NULL, *name = NULL;
|
||||
const char *m;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
m = strchr(s, '#');
|
||||
if (m) {
|
||||
name = strdup(m+1);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
buf = strndup(s, m - s);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
s = buf;
|
||||
}
|
||||
|
||||
r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (server_name)
|
||||
*server_name = TAKE_PTR(name);
|
||||
|
||||
return r;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include "in-addr-util.h"
|
||||
|
||||
int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue