Compare commits
48 Commits
dfc637d0ff
...
1008f5b069
Author | SHA1 | Date |
---|---|---|
Lennart Poettering | 1008f5b069 | |
Lennart Poettering | 21ad331873 | |
Lennart Poettering | 64a7fcc5cd | |
Lennart Poettering | 84fc961082 | |
Lennart Poettering | b0eb40cda4 | |
Lennart Poettering | fc8bc57f6b | |
Lennart Poettering | 4840807c6d | |
Lennart Poettering | 6293d958a4 | |
Lennart Poettering | 7848cb8c57 | |
Lennart Poettering | 670eed4c8c | |
Lennart Poettering | 74aaf59b1a | |
Lennart Poettering | f5fa352f1e | |
Yu Watanabe | fd8f865c9f | |
Zbigniew Jędrzejewski-Szmek | 547f724f7a | |
Zbigniew Jędrzejewski-Szmek | 540e0bad3e | |
Lennart Poettering | eaa2751685 | |
Lennart Poettering | 59c4bbfb93 | |
Lennart Poettering | b8cfa2da7c | |
Lennart Poettering | 441e0fdb90 | |
Lennart Poettering | 6ea0d25c57 | |
Lennart Poettering | 562b01e996 | |
Zbigniew Jędrzejewski-Szmek | 0a42426d79 | |
Yu Watanabe | 5431227400 | |
Yu Watanabe | a7df5cae54 | |
Yu Watanabe | 66f507e1ba | |
Yu Watanabe | 10fa21c0dc | |
Yu Watanabe | 8ff85383b4 | |
Yu Watanabe | a0887abbd8 | |
Yu Watanabe | 5e71868ced | |
Yu Watanabe | 11e9fec259 | |
Zbigniew Jędrzejewski-Szmek | 1b5b507cd2 | |
Yu Watanabe | 21266e60e9 | |
Yu Watanabe | b1476b5210 | |
Yu Watanabe | fe841414ef | |
Yu Watanabe | 9b9c5fff16 | |
Zbigniew Jędrzejewski-Szmek | a4ccce22d9 | |
Zbigniew Jędrzejewski-Szmek | b45c068dd8 | |
Zbigniew Jędrzejewski-Szmek | 0b3456428b | |
Lennart Poettering | 612ebf6c91 | |
Yu Watanabe | efdaeb88f0 | |
Yu Watanabe | 6d4bcea4ca | |
Yu Watanabe | 7f67b01e3f | |
Yu Watanabe | f576730256 | |
Yu Watanabe | e0e789c1e9 | |
Yu Watanabe | 51d9aec0ff | |
Yu Watanabe | 2e17fed5f3 | |
Yu Watanabe | cadc7ed2e2 | |
Yu Watanabe | 87bc687a8c |
2
TODO
2
TODO
|
@ -24,8 +24,6 @@ Features:
|
|||
|
||||
* in fd_get_path() if we see (deleted) then do stat and check for st_nlink
|
||||
|
||||
* add support for close_range() added in kernel 5.9
|
||||
|
||||
* Add service setting to run a service within the specified VRF. i.e. do the
|
||||
equivalent of "ip vrf exec".
|
||||
|
||||
|
|
117
man/bootctl.xml
117
man/bootctl.xml
|
@ -17,7 +17,7 @@
|
|||
|
||||
<refnamediv>
|
||||
<refname>bootctl</refname>
|
||||
<refpurpose>Control the firmware and boot manager settings</refpurpose>
|
||||
<refpurpose>Control EFI firmware boot settings and manage boot loader</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
|
@ -31,16 +31,18 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>bootctl</command> can check the EFI boot loader status, list available boot loaders and boot loader
|
||||
entries, and install, update, or remove the
|
||||
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> boot loader on the
|
||||
current system.</para>
|
||||
<para><command>bootctl</command> can check the EFI firmware and boot loader status, list and manage
|
||||
available boot loaders and boot loader entries, and install, update, or remove the
|
||||
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> boot
|
||||
loader on the current system.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Commands</title>
|
||||
<variablelist>
|
||||
<title>Generic EFI Firmware/Boot Loader Commands</title>
|
||||
|
||||
<para>These commands are available on any EFI system, regardless of the boot loader used.</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>status</option></term>
|
||||
|
||||
|
@ -49,7 +51,69 @@
|
|||
loaders and the current default boot loader entry. If no command is specified, this is the implied
|
||||
default.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>reboot-to-firmware</option> <optional><replaceable>BOOL</replaceable></optional></term>
|
||||
|
||||
<listitem><para>Query or set the "Reboot-Into-Firmware-Setup" flag of the EFI firmware. Takes a
|
||||
boolean argument which controls whether to show the firmware setup on next system reboot. If the
|
||||
argument is omitted shows the current status of the flag, or whether the flag is supported. This
|
||||
controls the same flag as <command>systemctl reboot --firmware-setup</command>, but is more
|
||||
low-level and allows setting the flag independently from actually requesting a
|
||||
reboot.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>systemd-efi-options</option> <optional><replaceable>STRING</replaceable></optional></term>
|
||||
|
||||
<listitem><para>When called without the optional argument, prints the current value of the
|
||||
<literal>SystemdOptions</literal> EFI variable. When called with an argument, sets the
|
||||
variable to that value. See
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
for the meaning of that variable.</para></listitem>
|
||||
</varlistentry>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Boot Loader Specification Commands</title>
|
||||
|
||||
<para>These commands are available for all boot loaders that implement the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> and/or the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>, such as
|
||||
<command>systemd-boot</command>.</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>list</option></term>
|
||||
|
||||
<listitem><para>Shows all available boot loader entries implementing the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>, as well as any
|
||||
other entries discovered or automatically generated by a boot loader implementing the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader
|
||||
Interface</ulink>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>set-default</option> <replaceable>ID</replaceable></term>
|
||||
<term><option>set-oneshot</option> <replaceable>ID</replaceable></term>
|
||||
|
||||
<listitem><para>Sets the default boot loader entry. Takes a single boot loader entry ID string as
|
||||
argument. The <option>set-oneshot</option> command will set the default entry only for the next boot,
|
||||
the <option>set-default</option> will set it persistently for all future boots.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title><command>systemd-boot</command> Commands</title>
|
||||
|
||||
<para>These commands manage the <command>systemd-boot</command> EFI boot loader, and do not work in
|
||||
conjunction with other boot loaders.</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>install</option></term>
|
||||
|
||||
|
@ -101,45 +165,6 @@
|
|||
information.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>systemd-efi-options</option> <optional><replaceable>STRING</replaceable></optional></term>
|
||||
|
||||
<listitem><para>When called without the optional argument, prints the current value of the
|
||||
<literal>SystemdOptions</literal> EFI variable. When called with an argument, sets the
|
||||
variable to that value. See
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
for the meaning of that variable.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>reboot-to-firmware</option> <optional><replaceable>BOOL</replaceable></optional></term>
|
||||
|
||||
<listitem><para>Query or set the "Reboot-Into-Firmware-Setup" flag of the EFI firmware. Takes a
|
||||
boolean argument which controls whether to show the firmware setup on next system reboot. If the
|
||||
argument is omitted shows the current status of the flag, or whether the flag is supported. This
|
||||
controls the same flag as <command>systemctl reboot --firmware-setup</command>, but is more
|
||||
low-level and allows setting the flag independently from actually requesting a
|
||||
reboot.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>list</option></term>
|
||||
|
||||
<listitem><para>Shows all available boot loader entries implementing the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
|
||||
Specification</ulink>, as well as any other entries discovered or automatically generated by the boot
|
||||
loader.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>set-default</option> <replaceable>ID</replaceable></term>
|
||||
<term><option>set-oneshot</option> <replaceable>ID</replaceable></term>
|
||||
|
||||
<listitem><para>Sets the default boot loader entry. Takes a single boot loader entry ID string as argument. The
|
||||
<option>set-oneshot</option> command will set the default entry only for the next boot, the
|
||||
<option>set-default</option> will set it persistently for all future boots.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
|
|
@ -64,6 +64,33 @@
|
|||
the invoking terminal is determined to be UTF-8 compatible).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='lesssecure'>
|
||||
<term><varname>$SYSTEMD_PAGERSECURE</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. When true, the "secure" mode of the pager is enabled; if
|
||||
false, disabled. If <varname>$SYSTEMD_PAGERSECURE</varname> is not set at all, secure mode is enabled
|
||||
if the effective UID is not the same as the owner of the login session, see <citerefentry
|
||||
project='man-pages'><refentrytitle>geteuid</refentrytitle><manvolnum>2</manvolnum></citerefentry> and
|
||||
<citerefentry><refentrytitle>sd_pid_get_owner_uid</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
||||
In secure mode, <option>LESSSECURE=1</option> will be set when invoking the pager, and the pager shall
|
||||
disable commands that open or create new files or start new subprocesses. When
|
||||
<varname>$SYSTEMD_PAGERSECURE</varname> is not set at all, pagers which are not known to implement
|
||||
secure mode will not be used. (Currently only
|
||||
<citerefentry><refentrytitle>less</refentrytitle><manvolnum>1</manvolnum></citerefentry> implements
|
||||
secure mode.)</para>
|
||||
|
||||
<para>Note: when commands are invoked with elevated privileges, for example under <citerefentry
|
||||
project='man-pages'><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry> or
|
||||
<citerefentry
|
||||
project='die-net'><refentrytitle>pkexec</refentrytitle><manvolnum>1</manvolnum></citerefentry>, care
|
||||
must be taken to ensure that unintended interactive features are not enabled. "Secure" mode for the
|
||||
pager may be enabled automatically as describe above. Setting <varname>SYSTEMD_PAGERSECURE=0</varname>
|
||||
or not removing it from the inherited environment allows the user to invoke arbitrary commands. Note
|
||||
that if the <varname>$SYSTEMD_PAGER</varname> or <varname>$PAGER</varname> variables are to be
|
||||
honoured, <varname>$SYSTEMD_PAGERSECURE</varname> must be set too. It might be reasonable to completly
|
||||
disable the pager using <option>--no-pager</option> instead.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id='colors'>
|
||||
<term><varname>$SYSTEMD_COLORS</varname></term>
|
||||
|
||||
|
|
|
@ -38,16 +38,16 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><function>sd_bus_message_read_array()</function> gives access to an element array in
|
||||
message <parameter>m</parameter>. The "read pointer" in the message must be right before an
|
||||
array of type <parameter>type</parameter>. As a special case, <parameter>type</parameter> may be
|
||||
<constant>NUL</constant>, in which case any type is acceptable. A pointer to the array data is
|
||||
returned in the parameter <parameter>ptr</parameter> and the size of array data (in bytes) is
|
||||
returned in the parameter <parameter>size</parameter>. If <parameter>size</parameter> is 0, a
|
||||
valid non-null pointer will be returned, but it may not be dereferenced. The data is aligned as
|
||||
appropriate for the data type. The data is part of the message — it may not be modified and is
|
||||
valid only as long as the message is referenced. After this function returns, the "read pointer"
|
||||
points at the next element after the array.</para>
|
||||
<para><function>sd_bus_message_read_array()</function> provides access to an array elements in the
|
||||
bus message <parameter>m</parameter>. The "read pointer" in the message must be right before an array of type
|
||||
<parameter>type</parameter>. As a special case, <parameter>type</parameter> may be
|
||||
<constant>NUL</constant>, in which case any trivial type is acceptable. A pointer to the array data is returned
|
||||
in the parameter <parameter>ptr</parameter> and the size of array data (in bytes) is returned in the
|
||||
parameter <parameter>size</parameter>. If the returned <parameter>size</parameter> parameter is 0, a
|
||||
valid non-null pointer will be returned as <parameter>ptr</parameter>, but it may not be
|
||||
dereferenced. The data is aligned as appropriate for the data type. The data is part of the message — it
|
||||
may not be modified and is valid only as long as the message is referenced. After this function returns,
|
||||
the "read pointer" points at the next element after the array.</para>
|
||||
|
||||
<para>Note that this function only supports arrays of trivial types, i.e. arrays of booleans, the various
|
||||
integer types, as well as floating point numbers. In particular it may not be used for arrays of strings,
|
||||
|
@ -58,9 +58,12 @@
|
|||
<title>Return Value</title>
|
||||
|
||||
<para>
|
||||
On success, <function>sd_bus_message_read_array()</function> returns 0 or
|
||||
a positive integer. On failure, it returns a negative errno-style error
|
||||
code.
|
||||
On success and when an array was read, <function>sd_bus_message_read_array()</function> returns an
|
||||
integer greater than zero. If invoked while inside a container element (such as an array, e.g. when
|
||||
operating on an array of arrays) and the final element of the outer container has been read already and
|
||||
the read pointer is thus behind the last element of the outer container this call returns 0 (and the
|
||||
returned pointer will be <constant>NULL</constant> and the size will be 0). On failure, it returns a
|
||||
negative errno-style error code.
|
||||
</para>
|
||||
|
||||
<refsect2>
|
||||
|
|
|
@ -2303,6 +2303,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
|||
<xi:include href="less-variables.xml" xpointer="pager"/>
|
||||
<xi:include href="less-variables.xml" xpointer="less"/>
|
||||
<xi:include href="less-variables.xml" xpointer="lesscharset"/>
|
||||
<xi:include href="less-variables.xml" xpointer="lesssecure"/>
|
||||
<xi:include href="less-variables.xml" xpointer="colors"/>
|
||||
<xi:include href="less-variables.xml" xpointer="urlify"/>
|
||||
</refsect1>
|
||||
|
|
|
@ -691,6 +691,7 @@
|
|||
<xi:include href="less-variables.xml" xpointer="pager"/>
|
||||
<xi:include href="less-variables.xml" xpointer="less"/>
|
||||
<xi:include href="less-variables.xml" xpointer="lesscharset"/>
|
||||
<xi:include href="less-variables.xml" xpointer="lesssecure"/>
|
||||
<xi:include href="less-variables.xml" xpointer="colors"/>
|
||||
<xi:include href="less-variables.xml" xpointer="urlify"/>
|
||||
|
||||
|
|
|
@ -533,6 +533,7 @@ foreach ident : [
|
|||
#include <signal.h>
|
||||
#include <sys/wait.h>'''],
|
||||
['mallinfo', '''#include <malloc.h>'''],
|
||||
['close_range', '''#include <unistd.h>'''],
|
||||
]
|
||||
|
||||
have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
|
||||
|
|
|
@ -4,7 +4,7 @@ SUBSYSTEM!="net", GOTO="net_setup_link_end"
|
|||
|
||||
IMPORT{builtin}="path_id"
|
||||
|
||||
ACTION!="add", GOTO="net_setup_link_end"
|
||||
ACTION=="remove", GOTO="net_setup_link_end"
|
||||
|
||||
IMPORT{builtin}="net_setup_link"
|
||||
|
||||
|
|
|
@ -46,9 +46,9 @@ SUBSYSTEM=="block", KERNEL=="nbd*", ENV{DEVTYPE}=="disk", TEST!="pid", ENV{SYSTE
|
|||
# http://cgit.freedesktop.org/systemd/systemd/tree/src/libudev/libudev-enumerate.c#n955
|
||||
|
||||
SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/$name"
|
||||
SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k"
|
||||
SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k", \
|
||||
ENV{SYSTEMD_WANTS}+="bluetooth.target", ENV{SYSTEMD_USER_WANTS}+="bluetooth.target"
|
||||
|
||||
SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_WANTS}+="bluetooth.target", ENV{SYSTEMD_USER_WANTS}+="bluetooth.target"
|
||||
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0b????:*", ENV{ID_SMARTCARD_READER}="1"
|
||||
ENV{ID_SMARTCARD_READER}=="?*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="smartcard.target", ENV{SYSTEMD_USER_WANTS}+="smartcard.target"
|
||||
SUBSYSTEM=="sound", KERNEL=="card*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sound.target", ENV{SYSTEMD_USER_WANTS}+="sound.target"
|
||||
|
|
|
@ -27,7 +27,7 @@ typedef void (*free_func_t)(void *p);
|
|||
size_t _n_ = n; \
|
||||
assert(!size_multiply_overflow(sizeof(t), _n_)); \
|
||||
assert(sizeof(t)*_n_ <= ALLOCA_MAX); \
|
||||
(t*) alloca(sizeof(t)*_n_); \
|
||||
(t*) alloca((sizeof(t)*_n_) ?: 1); \
|
||||
})
|
||||
|
||||
#define newa0(t, n) \
|
||||
|
@ -35,14 +35,14 @@ typedef void (*free_func_t)(void *p);
|
|||
size_t _n_ = n; \
|
||||
assert(!size_multiply_overflow(sizeof(t), _n_)); \
|
||||
assert(sizeof(t)*_n_ <= ALLOCA_MAX); \
|
||||
(t*) alloca0(sizeof(t)*_n_); \
|
||||
(t*) alloca0((sizeof(t)*_n_) ?: 1); \
|
||||
})
|
||||
|
||||
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
|
||||
|
||||
#define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
|
||||
|
||||
#define malloc0(n) (calloc(1, (n)))
|
||||
#define malloc0(n) (calloc(1, (n) ?: 1))
|
||||
|
||||
static inline void *mfree(void *memory) {
|
||||
free(memory);
|
||||
|
@ -65,7 +65,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
|
|||
void *_q_; \
|
||||
size_t _l_ = l; \
|
||||
assert(_l_ <= ALLOCA_MAX); \
|
||||
_q_ = alloca(_l_); \
|
||||
_q_ = alloca(_l_ ?: 1); \
|
||||
memcpy(_q_, p, _l_); \
|
||||
})
|
||||
|
||||
|
@ -135,7 +135,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
|
|||
char *_new_; \
|
||||
size_t _len_ = n; \
|
||||
assert(_len_ <= ALLOCA_MAX); \
|
||||
_new_ = alloca(_len_); \
|
||||
_new_ = alloca(_len_ ?: 1); \
|
||||
(void *) memset(_new_, 0, _len_); \
|
||||
})
|
||||
|
||||
|
@ -146,7 +146,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
|
|||
size_t _mask_ = (align) - 1; \
|
||||
size_t _size_ = size; \
|
||||
assert(_size_ <= ALLOCA_MAX); \
|
||||
_ptr_ = alloca(_size_ + _mask_); \
|
||||
_ptr_ = alloca((_size_ + _mask_) ?: 1); \
|
||||
(void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
|
||||
})
|
||||
|
||||
|
|
|
@ -16,22 +16,26 @@
|
|||
#include "strv.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#define VALID_CHARS_ENV_NAME \
|
||||
/* We follow bash for the character set. Different shells have different rules. */
|
||||
#define VALID_BASH_ENV_NAME_CHARS \
|
||||
DIGITS LETTERS \
|
||||
"_"
|
||||
|
||||
static bool env_name_is_valid_n(const char *e, size_t n) {
|
||||
const char *p;
|
||||
static bool printable_portable_character(char c) {
|
||||
/* POSIX.1-2008 specifies almost all ASCII characters as "portable". (Only DEL is excluded, and
|
||||
* additionally NUL and = are not allowed in variable names). We are stricter, and additionally
|
||||
* reject BEL, BS, HT, CR, LF, VT, FF and SPACE, i.e. all whitespace. */
|
||||
|
||||
return c >= '!' && c <= '~';
|
||||
}
|
||||
|
||||
static bool env_name_is_valid_n(const char *e, size_t n) {
|
||||
if (!e)
|
||||
return false;
|
||||
|
||||
if (n <= 0)
|
||||
return false;
|
||||
|
||||
if (e[0] >= '0' && e[0] <= '9')
|
||||
return false;
|
||||
|
||||
/* POSIX says the overall size of the environment block cannot
|
||||
* be > ARG_MAX, an individual assignment hence cannot be
|
||||
* either. Discounting the equal sign and trailing NUL this
|
||||
|
@ -40,8 +44,8 @@ static bool env_name_is_valid_n(const char *e, size_t n) {
|
|||
if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
|
||||
return false;
|
||||
|
||||
for (p = e; p < e + n; p++)
|
||||
if (!strchr(VALID_CHARS_ENV_NAME, *p))
|
||||
for (const char *p = e; p < e + n; p++)
|
||||
if (!printable_portable_character(*p) || *p == '=')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -546,7 +550,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
|
|||
word = e+1;
|
||||
state = WORD;
|
||||
|
||||
} else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) {
|
||||
} else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
|
||||
k = strnappend(r, word, e-word-1);
|
||||
if (!k)
|
||||
return NULL;
|
||||
|
@ -636,7 +640,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
|
|||
case VARIABLE_RAW:
|
||||
assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
|
||||
|
||||
if (!strchr(VALID_CHARS_ENV_NAME, *e)) {
|
||||
if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
|
||||
const char *t;
|
||||
|
||||
t = strv_env_get_n(env, word+1, e-word-1, flags);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "sort-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
@ -210,13 +211,102 @@ static int get_max_fd(void) {
|
|||
return (int) (m - 1);
|
||||
}
|
||||
|
||||
static int cmp_int(const int *a, const int *b) {
|
||||
return CMP(*a, *b);
|
||||
}
|
||||
|
||||
int close_all_fds(const int except[], size_t n_except) {
|
||||
static bool have_close_range = true; /* Assume we live in the future */
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
struct dirent *de;
|
||||
int r = 0;
|
||||
|
||||
assert(n_except == 0 || except);
|
||||
|
||||
if (have_close_range) {
|
||||
/* In the best case we have close_range() to close all fds between a start and an end fd,
|
||||
* which we can use on the "inverted" exception array, i.e. all intervals between all
|
||||
* adjacent pairs from the sorted exception array. This changes loop complexity from O(n)
|
||||
* where n is number of open fds to O(m⋅log(m)) where m is the number of fds to keep
|
||||
* open. Given that we assume n ≫ m that's preferable to us. */
|
||||
|
||||
if (n_except == 0) {
|
||||
/* Close everything. Yay! */
|
||||
|
||||
if (close_range(3, -1, 0) >= 0)
|
||||
return 1;
|
||||
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return -errno;
|
||||
|
||||
have_close_range = false;
|
||||
} else {
|
||||
_cleanup_free_ int *sorted_malloc = NULL;
|
||||
size_t n_sorted;
|
||||
int *sorted;
|
||||
|
||||
assert(n_except < SIZE_MAX);
|
||||
n_sorted = n_except + 1;
|
||||
|
||||
if (n_sorted > 64) /* Use heap for large numbers of fds, stack otherwise */
|
||||
sorted = sorted_malloc = new(int, n_sorted);
|
||||
else
|
||||
sorted = newa(int, n_sorted);
|
||||
|
||||
if (sorted) {
|
||||
int c = 0;
|
||||
|
||||
memcpy(sorted, except, n_except * sizeof(int));
|
||||
|
||||
/* Let's add fd 2 to the list of fds, to simplify the loop below, as this
|
||||
* allows us to cover the head of the array the same way as the body */
|
||||
sorted[n_sorted-1] = 2;
|
||||
|
||||
typesafe_qsort(sorted, n_sorted, cmp_int);
|
||||
|
||||
for (size_t i = 0; i < n_sorted-1; i++) {
|
||||
int start, end;
|
||||
|
||||
start = MAX(sorted[i], 2); /* The first three fds shall always remain open */
|
||||
end = MAX(sorted[i+1], 2);
|
||||
|
||||
assert(end >= start);
|
||||
|
||||
if (end - start <= 1)
|
||||
continue;
|
||||
|
||||
/* Close everything between the start and end fds (both of which shall stay open) */
|
||||
if (close_range(start + 1, end - 1, 0) < 0) {
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return -errno;
|
||||
|
||||
have_close_range = false;
|
||||
break;
|
||||
}
|
||||
|
||||
c += end - start - 1;
|
||||
}
|
||||
|
||||
if (have_close_range) {
|
||||
/* The loop succeeded. Let's now close everything beyond the end */
|
||||
|
||||
if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
|
||||
return c;
|
||||
|
||||
if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
|
||||
return c + 1;
|
||||
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return -errno;
|
||||
|
||||
have_close_range = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback on OOM or if close_range() is not supported */
|
||||
}
|
||||
|
||||
d = opendir("/proc/self/fd");
|
||||
if (!d) {
|
||||
int fd, max_fd;
|
||||
|
|
|
@ -71,6 +71,19 @@ const struct hash_ops trivial_hash_ops = {
|
|||
.compare = trivial_compare_func,
|
||||
};
|
||||
|
||||
const struct hash_ops trivial_hash_ops_free = {
|
||||
.hash = trivial_hash_func,
|
||||
.compare = trivial_compare_func,
|
||||
.free_key = free,
|
||||
};
|
||||
|
||||
const struct hash_ops trivial_hash_ops_free_free = {
|
||||
.hash = trivial_hash_func,
|
||||
.compare = trivial_compare_func,
|
||||
.free_key = free,
|
||||
.free_value = free,
|
||||
};
|
||||
|
||||
void uint64_hash_func(const uint64_t *p, struct siphash *state) {
|
||||
siphash24_compress(p, sizeof(uint64_t), state);
|
||||
}
|
||||
|
|
|
@ -88,6 +88,8 @@ extern const struct hash_ops path_hash_ops_free;
|
|||
void trivial_hash_func(const void *p, struct siphash *state);
|
||||
int trivial_compare_func(const void *a, const void *b) _const_;
|
||||
extern const struct hash_ops trivial_hash_ops;
|
||||
extern const struct hash_ops trivial_hash_ops_free;
|
||||
extern const struct hash_ops trivial_hash_ops_free_free;
|
||||
|
||||
/* 32bit values we can always just embed in the pointer itself, but in order to support 32bit archs we need store 64bit
|
||||
* values indirectly, since they don't fit in a pointer. */
|
||||
|
|
|
@ -1794,10 +1794,10 @@ int set_consume(Set *s, void *value) {
|
|||
return r;
|
||||
}
|
||||
|
||||
int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS) {
|
||||
int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v HASHMAP_DEBUG_PARAMS) {
|
||||
int r;
|
||||
|
||||
r = _hashmap_ensure_allocated(h, &string_hash_ops_free_free HASHMAP_DEBUG_PASS_ARGS);
|
||||
r = _hashmap_ensure_allocated(h, hash_ops HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -1828,14 +1828,14 @@ int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG
|
|||
return r;
|
||||
}
|
||||
|
||||
int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS) {
|
||||
int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS) {
|
||||
char *c;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(p);
|
||||
|
||||
r = _set_ensure_allocated(s, &string_hash_ops_free HASHMAP_DEBUG_PASS_ARGS);
|
||||
r = _set_ensure_allocated(s, hash_ops HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -1849,14 +1849,14 @@ int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS) {
|
|||
return set_consume(*s, c);
|
||||
}
|
||||
|
||||
int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS) {
|
||||
int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS) {
|
||||
int n = 0, r;
|
||||
char **i;
|
||||
|
||||
assert(s);
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
r = _set_put_strdup(s, *i HASHMAP_DEBUG_PASS_ARGS);
|
||||
r = _set_put_strdup_full(s, hash_ops, *i HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -153,8 +153,9 @@ static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *
|
|||
return hashmap_put(PLAIN_HASHMAP(h), key, value);
|
||||
}
|
||||
|
||||
int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS);
|
||||
#define hashmap_put_strdup(h, k, v) _hashmap_put_strdup(h, k, v HASHMAP_DEBUG_SRC_ARGS)
|
||||
int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v HASHMAP_DEBUG_PARAMS);
|
||||
#define hashmap_put_strdup_full(h, hash_ops, k, v) _hashmap_put_strdup_full(h, hash_ops, k, v HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define hashmap_put_strdup(h, k, v) hashmap_put_strdup_full(h, &string_hash_ops_free_free, k, v)
|
||||
|
||||
int hashmap_update(Hashmap *h, const void *key, void *value);
|
||||
static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
|
||||
|
|
|
@ -734,3 +734,49 @@ static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info)
|
|||
|
||||
# define rt_sigqueueinfo missing_rt_sigqueueinfo
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#define systemd_NR_close_range systemd_SC_arch_bias(436)
|
||||
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
#if defined __NR_close_range && __NR_close_range >= 0
|
||||
# if defined systemd_NR_close_range
|
||||
assert_cc(__NR_close_range == systemd_NR_close_range);
|
||||
# endif
|
||||
#else
|
||||
# if defined __NR_close_range
|
||||
# undef __NR_close_range
|
||||
# endif
|
||||
# if defined systemd_NR_close_range
|
||||
# define __NR_close_range systemd_NR_close_range
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !HAVE_CLOSE_RANGE
|
||||
static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) {
|
||||
# ifdef __NR_close_range
|
||||
/* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
|
||||
* userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to
|
||||
* wrap this syscall, but let's assume it's going to be similar to what they do for close(),
|
||||
* i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the
|
||||
* userspace wrapper. There's only one caveat for this: unlike for close() there's the special
|
||||
* UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse
|
||||
* any other negative values. */
|
||||
if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) {
|
||||
errno = -EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return syscall(__NR_close_range,
|
||||
(unsigned) first_fd,
|
||||
end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */
|
||||
flags);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define close_range missing_close_range
|
||||
#endif
|
||||
|
|
|
@ -128,10 +128,12 @@ int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HAS
|
|||
|
||||
int set_consume(Set *s, void *value);
|
||||
|
||||
int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strdup(s, p) _set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS)
|
||||
int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strdupv(s, l) _set_put_strdupv(s, l HASHMAP_DEBUG_SRC_ARGS)
|
||||
int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strdup_full(s, hash_ops, p) _set_put_strdup_full(s, hash_ops, p HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define set_put_strdup(s, p) set_put_strdup_full(s, &string_hash_ops_free, p)
|
||||
int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strdupv_full(s, hash_ops, l) _set_put_strdupv_full(s, hash_ops, l HASHMAP_DEBUG_SRC_ARGS)
|
||||
#define set_put_strdupv(s, l) set_put_strdupv_full(s, &string_hash_ops_free, l)
|
||||
|
||||
int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags);
|
||||
|
||||
|
|
|
@ -1014,24 +1014,25 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
printf("%s [OPTIONS...] COMMAND ...\n"
|
||||
"\n%sInstall/update/remove the systemd-boot EFI boot manager and list/select entries.%s\n"
|
||||
"\nBoot Loader Commands:\n"
|
||||
" status Show status of installed systemd-boot and EFI variables\n"
|
||||
printf("%1$s [OPTIONS...] COMMAND ...\n"
|
||||
"\n%5$sControl EFI firmware boot settings and manage boot loader.%6$s\n"
|
||||
"\n%3$sGeneric EFI Firmware/Boot Loader Commands:%4$s\n"
|
||||
" status Show status of installed boot loader and EFI variables\n"
|
||||
" reboot-to-firmware [BOOL]\n"
|
||||
" Query or set reboot-to-firmware EFI flag\n"
|
||||
" systemd-efi-options [STRING]\n"
|
||||
" Query or set system options string in EFI variable\n"
|
||||
"\n%3$sBoot Loader Specification Commands:%4$s\n"
|
||||
" list List boot loader entries\n"
|
||||
" set-default ID Set default boot loader entry\n"
|
||||
" set-oneshot ID Set default boot loader entry, for next boot only\n"
|
||||
"\n%3$ssystemd-boot Commands:%4$s\n"
|
||||
" install Install systemd-boot to the ESP and EFI variables\n"
|
||||
" update Update systemd-boot in the ESP and EFI variables\n"
|
||||
" remove Remove systemd-boot from the ESP and EFI variables\n"
|
||||
" is-installed Test whether systemd-boot is installed in the ESP\n"
|
||||
" random-seed Initialize random seed in ESP and EFI variables\n"
|
||||
" systemd-efi-options [STRING]\n"
|
||||
" Query or set system options string in EFI variable\n"
|
||||
" reboot-to-firmware [BOOL]\n"
|
||||
" Query or set reboot-to-firmware EFI flag\n"
|
||||
"\nBoot Loader Entries Commands:\n"
|
||||
" list List boot loader entries\n"
|
||||
" set-default ID Set default boot loader entry\n"
|
||||
" set-oneshot ID Set default boot loader entry, for next boot only\n"
|
||||
"\nOptions:\n"
|
||||
"\n%3$sOptions:%4$s\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Print version\n"
|
||||
" --esp-path=PATH Path to the EFI System Partition (ESP)\n"
|
||||
|
@ -1042,11 +1043,12 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" --no-pager Do not pipe output into a pager\n"
|
||||
" --graceful Don't fail when the ESP cannot be found or EFI\n"
|
||||
" variables cannot be written\n"
|
||||
"\nSee the %s for details.\n"
|
||||
"\nSee the %2$s for details.\n"
|
||||
, program_invocation_short_name
|
||||
, ansi_highlight()
|
||||
, ansi_normal()
|
||||
, link);
|
||||
, link
|
||||
, ansi_underline(), ansi_normal()
|
||||
, ansi_highlight(), ansi_normal()
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -894,6 +894,29 @@ static void device_propagate_reload_by_sysfs(Manager *m, const char *sysfs) {
|
|||
}
|
||||
}
|
||||
|
||||
static int device_remove_old(Manager *m, sd_device *dev) {
|
||||
_cleanup_free_ char *syspath_old = NULL, *e = NULL;
|
||||
const char *devpath_old;
|
||||
int r;
|
||||
|
||||
r = sd_device_get_property_value(dev, "DEVPATH_OLD", &devpath_old);
|
||||
if (r < 0) {
|
||||
log_device_debug_errno(dev, r, "Failed to get DEVPATH_OLD= property on 'move' uevent, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
syspath_old = path_join("/sys", devpath_old);
|
||||
if (!syspath_old)
|
||||
return log_oom();
|
||||
|
||||
r = unit_name_from_path(syspath_old, ".device", &e);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to generate unit name from old device path: %m");
|
||||
|
||||
device_update_found_by_sysfs(m, syspath_old, 0, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
|
||||
Manager *m = userdata;
|
||||
DeviceAction action;
|
||||
|
@ -918,6 +941,9 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
|
|||
if (!IN_SET(action, DEVICE_ACTION_ADD, DEVICE_ACTION_REMOVE, DEVICE_ACTION_MOVE))
|
||||
device_propagate_reload_by_sysfs(m, sysfs);
|
||||
|
||||
if (action == DEVICE_ACTION_MOVE)
|
||||
(void) device_remove_old(m, dev);
|
||||
|
||||
/* A change event can signal that a device is becoming ready, in particular if the device is using
|
||||
* the SYSTEMD_READY logic in udev so we need to reach the else block of the following if, even for
|
||||
* change events */
|
||||
|
|
|
@ -6068,7 +6068,12 @@ static int exec_runtime_add(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, ExecRuntime **ret) {
|
||||
static int exec_runtime_make(
|
||||
Manager *m,
|
||||
const ExecContext *c,
|
||||
const char *id,
|
||||
ExecRuntime **ret) {
|
||||
|
||||
_cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
|
||||
_cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 };
|
||||
int r;
|
||||
|
@ -6078,8 +6083,10 @@ static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, E
|
|||
assert(id);
|
||||
|
||||
/* It is not necessary to create ExecRuntime object. */
|
||||
if (!c->private_network && !c->private_tmp && !c->network_namespace_path)
|
||||
if (!c->private_network && !c->private_tmp && !c->network_namespace_path) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c->private_tmp &&
|
||||
!(prefixed_path_strv_contains(c->inaccessible_paths, "/tmp") &&
|
||||
|
@ -6115,14 +6122,20 @@ int exec_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool
|
|||
/* We already have a ExecRuntime object, let's increase the ref count and reuse it */
|
||||
goto ref;
|
||||
|
||||
if (!create)
|
||||
if (!create) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If not found, then create a new object. */
|
||||
r = exec_runtime_make(m, c, id, &rt);
|
||||
if (r <= 0)
|
||||
/* When r == 0, it is not necessary to create ExecRuntime object. */
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
/* When r == 0, it is not necessary to create ExecRuntime object. */
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ref:
|
||||
/* increment reference counter. */
|
||||
|
@ -6348,7 +6361,7 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
|
|||
r = safe_atoi(buf, &fdpair[1]);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-1=%s: %m", buf);
|
||||
if (!fdset_contains(fds, fdpair[0]))
|
||||
if (!fdset_contains(fds, fdpair[1]))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
|
||||
"exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", fdpair[1]);
|
||||
fdpair[1] = fdset_remove(fds, fdpair[1]);
|
||||
|
|
|
@ -3492,6 +3492,24 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
|||
assert(m);
|
||||
assert(f);
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
if (fdset_isempty(fds))
|
||||
log_debug("No file descriptors passed");
|
||||
else {
|
||||
int fd;
|
||||
|
||||
FDSET_FOREACH(fd, fds) {
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
|
||||
r = fd_get_path(fd, &fn);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Received serialized fd %i → %m", fd);
|
||||
else
|
||||
log_debug("Received serialized fd %i → %s", fd, strna(fn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("Deserializing state...");
|
||||
|
||||
/* If we are not in reload mode yet, enter it now. Not that this is recursive, a caller might already have
|
||||
|
|
|
@ -4795,8 +4795,13 @@ _public_ int sd_bus_message_read_array(
|
|||
assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -EOPNOTSUPP);
|
||||
|
||||
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
|
||||
if (r <= 0)
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
*ptr = NULL;
|
||||
*size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
c = message_get_last_container(m);
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ _public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumer
|
|||
else
|
||||
hashmap = &enumerator->nomatch_sysattr;
|
||||
|
||||
r = hashmap_put_strdup(hashmap, sysattr, value);
|
||||
r = hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
|
@ -133,7 +133,7 @@ _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enume
|
|||
assert_return(enumerator, -EINVAL);
|
||||
assert_return(property, -EINVAL);
|
||||
|
||||
r = hashmap_put_strdup(&enumerator->match_property, property, value);
|
||||
r = hashmap_put_strdup_full(&enumerator->match_property, &trivial_hash_ops_free_free, property, value);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -5,21 +5,22 @@
|
|||
#include "sd-login.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "errno-list.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "log.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "time-util.h"
|
||||
#include "util.h"
|
||||
#include "user-util.h"
|
||||
|
||||
static char* format_uids(char **buf, uid_t* uids, int count) {
|
||||
int pos = 0, k, inc;
|
||||
int pos = 0, inc;
|
||||
size_t size = (DECIMAL_STR_MAX(uid_t) + 1) * count + 1;
|
||||
|
||||
assert_se(*buf = malloc(size));
|
||||
|
||||
for (k = 0; k < count; k++) {
|
||||
for (int k = 0; k < count; k++) {
|
||||
sprintf(*buf + pos, "%s"UID_FMT"%n", k > 0 ? " " : "", uids[k], &inc);
|
||||
pos += inc;
|
||||
}
|
||||
|
@ -30,6 +31,10 @@ static char* format_uids(char **buf, uid_t* uids, int count) {
|
|||
return *buf;
|
||||
}
|
||||
|
||||
static const char *e(int r) {
|
||||
return r == 0 ? "OK" : errno_to_name(r);
|
||||
}
|
||||
|
||||
static void test_login(void) {
|
||||
_cleanup_close_pair_ int pair[2] = { -1, -1 };
|
||||
_cleanup_free_ char *pp = NULL, *qq = NULL,
|
||||
|
@ -39,65 +44,71 @@ static void test_login(void) {
|
|||
*seat = NULL, *session = NULL,
|
||||
*unit = NULL, *user_unit = NULL, *slice = NULL;
|
||||
int r;
|
||||
uid_t u, u2;
|
||||
char *t, **seats, **sessions;
|
||||
uid_t u, u2 = UID_INVALID;
|
||||
char *t, **seats = NULL, **sessions = NULL;
|
||||
|
||||
r = sd_pid_get_unit(0, &unit);
|
||||
assert_se(r >= 0 || r == -ENODATA);
|
||||
log_info("sd_pid_get_unit(0, …) → \"%s\"", strna(unit));
|
||||
log_info("sd_pid_get_unit(0, …) → %s / \"%s\"", e(r), strnull(unit));
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pid_get_user_unit(0, &user_unit);
|
||||
assert_se(r >= 0 || r == -ENODATA);
|
||||
log_info("sd_pid_get_user_unit(0, …) → \"%s\"", strna(user_unit));
|
||||
log_info("sd_pid_get_user_unit(0, …) → %s / \"%s\"", e(r), strnull(user_unit));
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pid_get_slice(0, &slice);
|
||||
assert_se(r >= 0 || r == -ENODATA);
|
||||
log_info("sd_pid_get_slice(0, …) → \"%s\"", strna(slice));
|
||||
log_info("sd_pid_get_slice(0, …) → %s / \"%s\"", e(r), strnull(slice));
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pid_get_owner_uid(0, &u2);
|
||||
log_info("sd_pid_get_owner_uid(0, …) → %s / "UID_FMT, e(r), u2);
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_pid_get_session(0, &session);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "sd_pid_get_session(0, …): %m");
|
||||
if (r == -ENODATA)
|
||||
log_info("Seems we are not running in a session, skipping some tests.");
|
||||
} else {
|
||||
log_info("sd_pid_get_session(0, …) → \"%s\"", session);
|
||||
log_info("sd_pid_get_session(0, …) → %s / \"%s\"", e(r), strnull(session));
|
||||
|
||||
assert_se(sd_pid_get_owner_uid(0, &u2) == 0);
|
||||
log_info("sd_pid_get_owner_uid(0, …) → "UID_FMT, u2);
|
||||
r = sd_pid_get_cgroup(0, &cgroup);
|
||||
log_info("sd_pid_get_cgroup(0, …) → %s / \"%s\"", e(r), strnull(cgroup));
|
||||
assert_se(r == 0);
|
||||
|
||||
assert_se(sd_pid_get_cgroup(0, &cgroup) == 0);
|
||||
log_info("sd_pid_get_cgroup(0, …) → \"%s\"", cgroup);
|
||||
r = sd_uid_get_display(u2, &display_session);
|
||||
log_info("sd_uid_get_display("UID_FMT", …) → %s / \"%s\"", u2, e(r), strnull(display_session));
|
||||
if (u2 == UID_INVALID)
|
||||
assert_se(r == -EINVAL);
|
||||
else
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
|
||||
r = sd_uid_get_display(u2, &display_session);
|
||||
assert_se(r >= 0 || r == -ENODATA);
|
||||
log_info("sd_uid_get_display("UID_FMT", …) → \"%s\"",
|
||||
u2, strnull(display_session));
|
||||
assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0);
|
||||
sd_peer_get_session(pair[0], &pp);
|
||||
sd_peer_get_session(pair[1], &qq);
|
||||
assert_se(streq_ptr(pp, qq));
|
||||
|
||||
assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0);
|
||||
sd_peer_get_session(pair[0], &pp);
|
||||
sd_peer_get_session(pair[1], &qq);
|
||||
assert_se(streq_ptr(pp, qq));
|
||||
|
||||
r = sd_uid_get_sessions(u2, false, &sessions);
|
||||
r = sd_uid_get_sessions(u2, false, &sessions);
|
||||
assert_se(t = strv_join(sessions, " "));
|
||||
log_info("sd_uid_get_sessions("UID_FMT", …) → %s \"%s\"", u2, e(r), t);
|
||||
if (u2 == UID_INVALID)
|
||||
assert_se(r == -EINVAL);
|
||||
else {
|
||||
assert_se(r >= 0);
|
||||
assert_se(r == (int) strv_length(sessions));
|
||||
assert_se(t = strv_join(sessions, " "));
|
||||
strv_free(sessions);
|
||||
log_info("sd_uid_get_sessions("UID_FMT", …) → [%i] \"%s\"", u2, r, t);
|
||||
free(t);
|
||||
}
|
||||
sessions = strv_free(sessions);
|
||||
free(t);
|
||||
|
||||
assert_se(r == sd_uid_get_sessions(u2, false, NULL));
|
||||
assert_se(r == sd_uid_get_sessions(u2, false, NULL));
|
||||
|
||||
r = sd_uid_get_seats(u2, false, &seats);
|
||||
r = sd_uid_get_seats(u2, false, &seats);
|
||||
assert_se(t = strv_join(seats, " "));
|
||||
log_info("sd_uid_get_seats("UID_FMT", …) → %s \"%s\"", u2, e(r), t);
|
||||
if (u2 == UID_INVALID)
|
||||
assert_se(r == -EINVAL);
|
||||
else {
|
||||
assert_se(r >= 0);
|
||||
assert_se(r == (int) strv_length(seats));
|
||||
assert_se(t = strv_join(seats, " "));
|
||||
strv_free(seats);
|
||||
log_info("sd_uid_get_seats("UID_FMT", …) → [%i] \"%s\"", u2, r, t);
|
||||
free(t);
|
||||
|
||||
assert_se(r == sd_uid_get_seats(u2, false, NULL));
|
||||
}
|
||||
seats = strv_free(seats);
|
||||
free(t);
|
||||
|
||||
assert_se(r == sd_uid_get_seats(u2, false, NULL));
|
||||
|
||||
if (session) {
|
||||
r = sd_session_is_active(session);
|
||||
|
@ -109,7 +120,7 @@ static void test_login(void) {
|
|||
log_info("sd_session_is_remote(\"%s\") → %s", session, yes_no(r));
|
||||
|
||||
r = sd_session_get_state(session, &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(r == 0);
|
||||
log_info("sd_session_get_state(\"%s\") → \"%s\"", session, state);
|
||||
|
||||
assert_se(sd_session_get_uid(session, &u) >= 0);
|
||||
|
@ -123,16 +134,16 @@ static void test_login(void) {
|
|||
log_info("sd_session_get_class(\"%s\") → \"%s\"", session, class);
|
||||
|
||||
r = sd_session_get_display(session, &display);
|
||||
assert_se(r >= 0 || r == -ENODATA);
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
log_info("sd_session_get_display(\"%s\") → \"%s\"", session, strna(display));
|
||||
|
||||
r = sd_session_get_remote_user(session, &remote_user);
|
||||
assert_se(r >= 0 || r == -ENODATA);
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
log_info("sd_session_get_remote_user(\"%s\") → \"%s\"",
|
||||
session, strna(remote_user));
|
||||
|
||||
r = sd_session_get_remote_host(session, &remote_host);
|
||||
assert_se(r >= 0 || r == -ENODATA);
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
log_info("sd_session_get_remote_host(\"%s\") → \"%s\"",
|
||||
session, strna(remote_host));
|
||||
|
||||
|
@ -161,7 +172,7 @@ static void test_login(void) {
|
|||
assert_se(r == -ENODATA);
|
||||
}
|
||||
|
||||
assert_se(sd_uid_get_state(u, &state2) >= 0);
|
||||
assert_se(sd_uid_get_state(u, &state2) == 0);
|
||||
log_info("sd_uid_get_state("UID_FMT", …) → %s", u, state2);
|
||||
}
|
||||
|
||||
|
@ -173,11 +184,11 @@ static void test_login(void) {
|
|||
assert_se(sd_uid_is_on_seat(u, 0, seat) > 0);
|
||||
|
||||
r = sd_seat_get_active(seat, &session2, &u2);
|
||||
assert_se(r >= 0);
|
||||
assert_se(r == 0);
|
||||
log_info("sd_seat_get_active(\"%s\", …) → \"%s\", "UID_FMT, seat, session2, u2);
|
||||
|
||||
r = sd_uid_is_on_seat(u, 1, seat);
|
||||
assert_se(r >= 0);
|
||||
assert_se(IN_SET(r, 0, 1));
|
||||
assert_se(!!r == streq(session, session2));
|
||||
|
||||
r = sd_seat_get_sessions(seat, &sessions, &uids, &n);
|
||||
|
@ -185,8 +196,8 @@ static void test_login(void) {
|
|||
assert_se(r == (int) strv_length(sessions));
|
||||
assert_se(t = strv_join(sessions, " "));
|
||||
strv_free(sessions);
|
||||
log_info("sd_seat_get_sessions(\"%s\", …) → %i, \"%s\", [%i] {%s}",
|
||||
seat, r, t, n, format_uids(&buf, uids, n));
|
||||
log_info("sd_seat_get_sessions(\"%s\", …) → %s, \"%s\", [%u] {%s}",
|
||||
seat, e(r), t, n, format_uids(&buf, uids, n));
|
||||
free(t);
|
||||
|
||||
assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r);
|
||||
|
@ -204,7 +215,7 @@ static void test_login(void) {
|
|||
|
||||
r = sd_seat_get_active(NULL, &t, NULL);
|
||||
assert_se(IN_SET(r, 0, -ENODATA));
|
||||
log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s", strnull(t));
|
||||
log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s / \"%s\"", e(r), strnull(t));
|
||||
free(t);
|
||||
|
||||
r = sd_get_sessions(&sessions);
|
||||
|
@ -244,13 +255,11 @@ static void test_login(void) {
|
|||
|
||||
static void test_monitor(void) {
|
||||
sd_login_monitor *m = NULL;
|
||||
unsigned n;
|
||||
int r;
|
||||
|
||||
r = sd_login_monitor_new("session", &m);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_login_monitor_new("session", &m) == 0);
|
||||
|
||||
for (n = 0; n < 5; n++) {
|
||||
for (unsigned n = 0; n < 5; n++) {
|
||||
struct pollfd pollfd = {};
|
||||
usec_t timeout, nw;
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#define ADDRESSES_PER_LINK_MAX 2048U
|
||||
#define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
|
||||
|
||||
int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret) {
|
||||
int generate_ipv6_eui_64_address(const Link *link, struct in6_addr *ret) {
|
||||
assert(link);
|
||||
assert(ret);
|
||||
|
||||
|
@ -135,20 +135,6 @@ Address *address_free(Address *address) {
|
|||
return mfree(address);
|
||||
}
|
||||
|
||||
static uint32_t address_prefix(const Address *a) {
|
||||
assert(a);
|
||||
|
||||
/* make sure we don't try to shift by 32.
|
||||
* See ISO/IEC 9899:TC3 § 6.5.7.3. */
|
||||
if (a->prefixlen == 0)
|
||||
return 0;
|
||||
|
||||
if (a->in_addr_peer.in.s_addr != 0)
|
||||
return be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
|
||||
else
|
||||
return be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
|
||||
}
|
||||
|
||||
void address_hash_func(const Address *a, struct siphash *state) {
|
||||
assert(a);
|
||||
|
||||
|
@ -156,16 +142,16 @@ void address_hash_func(const Address *a, struct siphash *state) {
|
|||
|
||||
switch (a->family) {
|
||||
case AF_INET:
|
||||
siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
|
||||
|
||||
/* peer prefix */
|
||||
uint32_t prefix = address_prefix(a);
|
||||
siphash24_compress(&prefix, sizeof(prefix), state);
|
||||
siphash24_compress(&a->broadcast, sizeof(a->broadcast), state);
|
||||
siphash24_compress_string(a->label, state);
|
||||
|
||||
_fallthrough_;
|
||||
case AF_INET6:
|
||||
siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
|
||||
/* local address */
|
||||
siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
|
||||
/* peer address */
|
||||
siphash24_compress(&a->in_addr_peer, FAMILY_ADDRESS_SIZE(a->family), state);
|
||||
|
||||
break;
|
||||
default:
|
||||
|
@ -184,19 +170,25 @@ int address_compare_func(const Address *a1, const Address *a2) {
|
|||
switch (a1->family) {
|
||||
/* use the same notion of equality as the kernel does */
|
||||
case AF_INET:
|
||||
r = CMP(a1->prefixlen, a2->prefixlen);
|
||||
r = CMP(a1->broadcast.s_addr, a2->broadcast.s_addr);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
uint32_t prefix1 = address_prefix(a1);
|
||||
uint32_t prefix2 = address_prefix(a2);
|
||||
r = CMP(prefix1, prefix2);
|
||||
r = strcmp_ptr(a1->label, a2->label);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
_fallthrough_;
|
||||
case AF_INET6:
|
||||
return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
|
||||
r = CMP(a1->prefixlen, a2->prefixlen);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return memcmp(&a1->in_addr_peer, &a2->in_addr_peer, FAMILY_ADDRESS_SIZE(a1->family));
|
||||
default:
|
||||
/* treat any other address family as AF_UNSPEC */
|
||||
return 0;
|
||||
|
@ -205,7 +197,7 @@ int address_compare_func(const Address *a1, const Address *a2) {
|
|||
|
||||
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free);
|
||||
|
||||
bool address_equal(Address *a1, Address *a2) {
|
||||
bool address_equal(const Address *a1, const Address *a2) {
|
||||
if (a1 == a2)
|
||||
return true;
|
||||
|
||||
|
@ -274,25 +266,22 @@ static int address_set_masquerade(Address *address, bool add) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int address_add_internal(Link *link, Set **addresses,
|
||||
int family,
|
||||
const union in_addr_union *in_addr,
|
||||
unsigned char prefixlen,
|
||||
Address **ret) {
|
||||
static int address_add_internal(Link *link, Set **addresses, const Address *in, Address **ret) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(addresses);
|
||||
assert(in_addr);
|
||||
assert(in);
|
||||
|
||||
r = address_new(&address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
address->family = family;
|
||||
address->in_addr = *in_addr;
|
||||
address->prefixlen = prefixlen;
|
||||
r = address_copy(address, in);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Consider address tentative until we get the real flags from the kernel */
|
||||
address->flags = IFA_F_TENTATIVE;
|
||||
|
||||
|
@ -310,18 +299,21 @@ static int address_add_internal(Link *link, Set **addresses,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
|
||||
return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
|
||||
static int address_add_foreign(Link *link, const Address *in, Address **ret) {
|
||||
return address_add_internal(link, &link->addresses_foreign, in, ret);
|
||||
}
|
||||
|
||||
static int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
|
||||
static int address_add(Link *link, const Address *in, Address **ret) {
|
||||
Address *address;
|
||||
int r;
|
||||
|
||||
r = address_get(link, family, in_addr, prefixlen, &address);
|
||||
assert(link);
|
||||
assert(in);
|
||||
|
||||
r = address_get(link, in, &address);
|
||||
if (r == -ENOENT) {
|
||||
/* Address does not exist, create a new one */
|
||||
r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
|
||||
r = address_add_internal(link, &link->addresses, in, &address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (r == 0) {
|
||||
|
@ -343,24 +335,19 @@ static int address_add(Link *link, int family, const union in_addr_union *in_add
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int address_update(
|
||||
Address *address,
|
||||
unsigned char flags,
|
||||
unsigned char scope,
|
||||
const struct ifa_cacheinfo *cinfo) {
|
||||
|
||||
static int address_update(Address *address, const Address *src) {
|
||||
bool ready;
|
||||
int r;
|
||||
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
assert(cinfo);
|
||||
assert(src);
|
||||
|
||||
ready = address_is_ready(address);
|
||||
|
||||
address->flags = flags;
|
||||
address->scope = scope;
|
||||
address->cinfo = *cinfo;
|
||||
address->flags = src->flags;
|
||||
address->scope = src->scope;
|
||||
address->cinfo = src->cinfo;
|
||||
|
||||
if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||
return 0;
|
||||
|
@ -412,31 +399,20 @@ static int address_drop(Address *address) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int address_get(Link *link,
|
||||
int family,
|
||||
const union in_addr_union *in_addr,
|
||||
unsigned char prefixlen,
|
||||
Address **ret) {
|
||||
|
||||
Address address, *existing;
|
||||
int address_get(Link *link, const Address *in, Address **ret) {
|
||||
Address *existing;
|
||||
|
||||
assert(link);
|
||||
assert(in_addr);
|
||||
assert(in);
|
||||
|
||||
address = (Address) {
|
||||
.family = family,
|
||||
.in_addr = *in_addr,
|
||||
.prefixlen = prefixlen,
|
||||
};
|
||||
|
||||
existing = set_get(link->addresses, &address);
|
||||
existing = set_get(link->addresses, in);
|
||||
if (existing) {
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 1;
|
||||
}
|
||||
|
||||
existing = set_get(link->addresses_foreign, &address);
|
||||
existing = set_get(link->addresses_foreign, in);
|
||||
if (existing) {
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
|
@ -491,7 +467,7 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
|
|||
}
|
||||
|
||||
int address_remove(
|
||||
Address *address,
|
||||
const Address *address,
|
||||
Link *link,
|
||||
link_netlink_message_handler_t callback) {
|
||||
|
||||
|
@ -536,7 +512,7 @@ int address_remove(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool link_is_static_address_configured(Link *link, Address *address) {
|
||||
static bool link_is_static_address_configured(const Link *link, const Address *address) {
|
||||
Address *net_address;
|
||||
|
||||
assert(link);
|
||||
|
@ -548,14 +524,11 @@ static bool link_is_static_address_configured(Link *link, Address *address) {
|
|||
ORDERED_HASHMAP_FOREACH(net_address, link->network->addresses_by_section)
|
||||
if (address_equal(net_address, address))
|
||||
return true;
|
||||
else if (address->family == AF_INET6 && net_address->family == AF_INET6 &&
|
||||
in_addr_equal(AF_INET6, &address->in_addr, &net_address->in_addr_peer) > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool link_address_is_dynamic(Link *link, Address *address) {
|
||||
static bool link_address_is_dynamic(const Link *link, const Address *address) {
|
||||
Route *route;
|
||||
|
||||
assert(link);
|
||||
|
@ -649,7 +622,7 @@ int link_drop_foreign_addresses(Link *link) {
|
|||
continue;
|
||||
|
||||
if (link_is_static_address_configured(link, address)) {
|
||||
k = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
|
||||
k = address_add(link, address, NULL);
|
||||
if (k < 0) {
|
||||
log_link_error_errno(link, k, "Failed to add address: %m");
|
||||
if (r >= 0)
|
||||
|
@ -784,7 +757,7 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
|
|||
static int ipv4_dad_configure(Address *address);
|
||||
|
||||
int address_configure(
|
||||
Address *address,
|
||||
const Address *address,
|
||||
Link *link,
|
||||
link_netlink_message_handler_t callback,
|
||||
bool update,
|
||||
|
@ -804,7 +777,7 @@ int address_configure(
|
|||
assert(callback);
|
||||
|
||||
/* If this is a new address, then refuse adding more than the limit */
|
||||
if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
|
||||
if (address_get(link, address, NULL) <= 0 &&
|
||||
set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
|
||||
return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
|
||||
"Too many addresses are configured, refusing: %m");
|
||||
|
@ -874,14 +847,10 @@ int address_configure(
|
|||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append IFA_CACHEINFO attribute: %m");
|
||||
|
||||
if (address->family == AF_INET6 && !in_addr_is_null(address->family, &address->in_addr_peer))
|
||||
r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, &a);
|
||||
else
|
||||
r = address_add(link, address->family, &address->in_addr, address->prefixlen, &a);
|
||||
r = address_add(link, address, &a);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not add address: %m");
|
||||
|
||||
a->scope = address->scope;
|
||||
r = address_set_masquerade(a, true);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
|
||||
|
@ -987,7 +956,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int static_address_configure(Address *address, Link *link, bool update) {
|
||||
static int static_address_configure(const Address *address, Link *link, bool update) {
|
||||
Address *ret;
|
||||
int r;
|
||||
|
||||
|
@ -1025,11 +994,7 @@ int link_set_addresses(Link *link) {
|
|||
ORDERED_HASHMAP_FOREACH(ad, link->network->addresses_by_section) {
|
||||
bool update;
|
||||
|
||||
if (ad->family == AF_INET6 && !in_addr_is_null(ad->family, &ad->in_addr_peer))
|
||||
update = address_get(link, ad->family, &ad->in_addr_peer, ad->prefixlen, NULL) > 0;
|
||||
else
|
||||
update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0;
|
||||
|
||||
update = address_get(link, ad, NULL) > 0;
|
||||
r = static_address_configure(ad, link, update);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -1078,16 +1043,16 @@ int link_set_addresses(Link *link) {
|
|||
}
|
||||
|
||||
int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
_cleanup_(address_freep) Address *tmp = NULL;
|
||||
_cleanup_free_ char *buf = NULL, *buf_peer = NULL;
|
||||
Link *link = NULL;
|
||||
uint16_t type;
|
||||
unsigned char flags, prefixlen, scope;
|
||||
union in_addr_union in_addr = IN_ADDR_NULL;
|
||||
struct ifa_cacheinfo cinfo;
|
||||
unsigned char flags;
|
||||
Address *address = NULL;
|
||||
char valid_buf[FORMAT_TIMESPAN_MAX];
|
||||
const char *valid_str = NULL;
|
||||
int ifindex, family, r;
|
||||
int ifindex, r;
|
||||
bool has_peer = false;
|
||||
|
||||
assert(rtnl);
|
||||
assert(message);
|
||||
|
@ -1128,22 +1093,26 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_addr_get_family(message, &family);
|
||||
r = address_new(&tmp);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = sd_rtnl_message_addr_get_family(message, &tmp->family);
|
||||
if (r < 0) {
|
||||
log_link_warning(link, "rtnl: received address message without family, ignoring.");
|
||||
return 0;
|
||||
} else if (!IN_SET(family, AF_INET, AF_INET6)) {
|
||||
log_link_debug(link, "rtnl: received address message with invalid family '%i', ignoring.", family);
|
||||
} else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
|
||||
log_link_debug(link, "rtnl: received address message with invalid family '%i', ignoring.", tmp->family);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen);
|
||||
r = sd_rtnl_message_addr_get_prefixlen(message, &tmp->prefixlen);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received address message without prefixlen, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_addr_get_scope(message, &scope);
|
||||
r = sd_rtnl_message_addr_get_scope(message, &tmp->scope);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received address message without scope, ignoring: %m");
|
||||
return 0;
|
||||
|
@ -1154,21 +1123,61 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
log_link_warning_errno(link, r, "rtnl: received address message without flags, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
tmp->flags = flags;
|
||||
|
||||
switch (family) {
|
||||
switch (tmp->family) {
|
||||
case AF_INET:
|
||||
r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in);
|
||||
r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &tmp->in_addr.in);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in_addr(message, IFA_ADDRESS, &tmp->in_addr_peer.in);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: could not get peer address from address message, ignoring: %m");
|
||||
return 0;
|
||||
} else if (r >= 0) {
|
||||
if (in4_addr_equal(&tmp->in_addr.in, &tmp->in_addr_peer.in))
|
||||
tmp->in_addr_peer = IN_ADDR_NULL;
|
||||
else
|
||||
has_peer = true;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in_addr(message, IFA_BROADCAST, &tmp->broadcast);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: could not get broadcast from address message, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_string_strdup(message, IFA_LABEL, &tmp->label);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: could not get label from address message, ignoring: %m");
|
||||
return 0;
|
||||
} else if (r >= 0 && streq_ptr(tmp->label, link->ifname))
|
||||
tmp->label = mfree(tmp->label);
|
||||
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
|
||||
r = sd_netlink_message_read_in6_addr(message, IFA_LOCAL, &tmp->in_addr.in6);
|
||||
if (r >= 0) {
|
||||
/* Have peer address. */
|
||||
r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &tmp->in_addr_peer.in6);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: could not get peer address from address message, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
has_peer = true;
|
||||
} else if (r == -ENODATA) {
|
||||
/* Does not have peer address. */
|
||||
r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &tmp->in_addr.in6);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
log_link_warning_errno(link, r, "rtnl: could not get local address from address message, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1178,40 +1187,43 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
assert_not_reached("Received unsupported address family");
|
||||
}
|
||||
|
||||
(void) in_addr_to_string(family, &in_addr, &buf);
|
||||
(void) in_addr_to_string(tmp->family, &tmp->in_addr, &buf);
|
||||
(void) in_addr_to_string(tmp->family, &tmp->in_addr_peer, &buf_peer);
|
||||
|
||||
r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
|
||||
r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &tmp->cinfo);
|
||||
if (r < 0 && r != -ENODATA) {
|
||||
log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m");
|
||||
return 0;
|
||||
} else if (r >= 0 && cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
|
||||
} else if (r >= 0 && tmp->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
|
||||
valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
|
||||
cinfo.ifa_valid * USEC_PER_SEC,
|
||||
tmp->cinfo.ifa_valid * USEC_PER_SEC,
|
||||
USEC_PER_SEC);
|
||||
|
||||
(void) address_get(link, family, &in_addr, prefixlen, &address);
|
||||
(void) address_get(link, tmp, &address);
|
||||
|
||||
switch (type) {
|
||||
case RTM_NEWADDR:
|
||||
if (address)
|
||||
log_link_debug(link, "Remembering updated address: %s/%u (valid %s%s)",
|
||||
strnull(buf), prefixlen,
|
||||
log_link_debug(link, "Remembering updated address: %s%s%s/%u (valid %s%s)",
|
||||
strnull(buf), has_peer ? " peer " : "",
|
||||
has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
|
||||
valid_str ? "for " : "forever", strempty(valid_str));
|
||||
else {
|
||||
/* An address appeared that we did not request */
|
||||
r = address_add_foreign(link, family, &in_addr, prefixlen, &address);
|
||||
r = address_add_foreign(link, tmp, &address);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Failed to remember foreign address %s/%u, ignoring: %m",
|
||||
strnull(buf), prefixlen);
|
||||
strnull(buf), tmp->prefixlen);
|
||||
return 0;
|
||||
} else
|
||||
log_link_debug(link, "Remembering foreign address: %s/%u (valid %s%s)",
|
||||
strnull(buf), prefixlen,
|
||||
log_link_debug(link, "Remembering foreign address: %s%s%s/%u (valid %s%s)",
|
||||
strnull(buf), has_peer ? " peer " : "",
|
||||
has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
|
||||
valid_str ? "for " : "forever", strempty(valid_str));
|
||||
}
|
||||
|
||||
/* address_update() logs internally, so we don't need to here. */
|
||||
r = address_update(address, flags, scope, &cinfo);
|
||||
r = address_update(address, tmp);
|
||||
if (r < 0)
|
||||
link_enter_failed(link);
|
||||
|
||||
|
@ -1219,13 +1231,15 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
|
||||
case RTM_DELADDR:
|
||||
if (address) {
|
||||
log_link_debug(link, "Forgetting address: %s/%u (valid %s%s)",
|
||||
strnull(buf), prefixlen,
|
||||
log_link_debug(link, "Forgetting address: %s%s%s/%u (valid %s%s)",
|
||||
strnull(buf), has_peer ? " peer " : "",
|
||||
has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
|
||||
valid_str ? "for " : "forever", strempty(valid_str));
|
||||
(void) address_drop(address);
|
||||
} else
|
||||
log_link_debug(link, "Kernel removed an address we don't remember: %s/%u (valid %s%s), ignoring.",
|
||||
strnull(buf), prefixlen,
|
||||
log_link_debug(link, "Kernel removed an address we don't remember: %s%s%s/%u (valid %s%s), ignoring.",
|
||||
strnull(buf), has_peer ? " peer " : "",
|
||||
has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
|
||||
valid_str ? "for " : "forever", strempty(valid_str));
|
||||
|
||||
break;
|
||||
|
@ -1264,11 +1278,8 @@ int link_deserialize_addresses(Link *link, const char *addresses) {
|
|||
assert(link);
|
||||
|
||||
for (const char *p = addresses;; ) {
|
||||
_cleanup_(address_freep) Address *tmp = NULL;
|
||||
_cleanup_free_ char *address_str = NULL;
|
||||
union in_addr_union address;
|
||||
unsigned char prefixlen;
|
||||
char *prefixlen_str;
|
||||
int family;
|
||||
|
||||
r = extract_first_word(&p, &address_str, NULL, 0);
|
||||
if (r < 0)
|
||||
|
@ -1276,28 +1287,19 @@ int link_deserialize_addresses(Link *link, const char *addresses) {
|
|||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
prefixlen_str = strchr(address_str, '/');
|
||||
if (!prefixlen_str) {
|
||||
log_link_debug(link, "Failed to parse address and prefix length, ignoring: %s", address_str);
|
||||
continue;
|
||||
}
|
||||
*prefixlen_str++ = '\0';
|
||||
|
||||
r = sscanf(prefixlen_str, "%hhu", &prefixlen);
|
||||
if (r != 1) {
|
||||
log_link_debug(link, "Failed to parse prefixlen: %s", prefixlen_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = in_addr_from_string_auto(address_str, &family, &address);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Failed to parse address: %s", address_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = address_add(link, family, &address, prefixlen, NULL);
|
||||
r = address_new(&tmp);
|
||||
if (r < 0)
|
||||
log_link_debug_errno(link, r, "Failed to add address: %m");
|
||||
return log_oom();
|
||||
|
||||
r = in_addr_prefix_from_string_auto(address_str, &tmp->family, &tmp->in_addr, &tmp->prefixlen);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Failed to parse address, ignoring: %s", address_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = address_add(link, tmp, NULL);
|
||||
if (r < 0)
|
||||
log_link_debug_errno(link, r, "Failed to add address %s, ignoring: %m", address_str);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1580,9 +1582,6 @@ int config_parse_address(
|
|||
else
|
||||
n->in_addr_peer = buffer;
|
||||
|
||||
if (n->family == AF_INET && n->broadcast.s_addr == 0 && n->prefixlen <= 30)
|
||||
n->broadcast.s_addr = n->in_addr.in.s_addr | htobe32(0xfffffffflu >> n->prefixlen);
|
||||
|
||||
n = NULL;
|
||||
|
||||
return 0;
|
||||
|
@ -1854,6 +1853,25 @@ static int address_section_verify(Address *address) {
|
|||
address->section->filename, address->section->line);
|
||||
}
|
||||
|
||||
if (address->family == AF_INET && in_addr_is_null(address->family, &address->in_addr_peer) &&
|
||||
address->broadcast.s_addr == 0 && address->prefixlen <= 30)
|
||||
address->broadcast.s_addr = address->in_addr.in.s_addr | htobe32(0xfffffffflu >> address->prefixlen);
|
||||
else if (address->broadcast.s_addr != 0) {
|
||||
log_warning("%s: broadcast address is set for IPv6 address or IPv4 address with prefixlength larger than 30. "
|
||||
"Ignoring Broadcast= setting in the [Address] section from line %u.",
|
||||
address->section->filename, address->section->line);
|
||||
|
||||
address->broadcast.s_addr = 0;
|
||||
}
|
||||
|
||||
if (address->family == AF_INET6 && address->label) {
|
||||
log_warning("%s: address label is set for IPv6 address in the [Address] section from line %u. "
|
||||
"Ignoring Label= setting.",
|
||||
address->section->filename, address->section->line);
|
||||
|
||||
address->label = mfree(address->label);
|
||||
}
|
||||
|
||||
if (in_addr_is_localhost(address->family, &address->in_addr) > 0 &&
|
||||
(address->family == AF_INET || !address->scope_set)) {
|
||||
/* For IPv4, scope must be always RT_SCOPE_HOST.
|
||||
|
|
|
@ -48,14 +48,14 @@ typedef struct Address {
|
|||
|
||||
int address_new(Address **ret);
|
||||
Address *address_free(Address *address);
|
||||
int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
|
||||
int address_get(Link *link, const Address *in, Address **ret);
|
||||
bool address_exists(Link *link, int family, const union in_addr_union *in_addr);
|
||||
int address_configure(Address *address, Link *link, link_netlink_message_handler_t callback, bool update, Address **ret);
|
||||
int address_remove(Address *address, Link *link, link_netlink_message_handler_t callback);
|
||||
bool address_equal(Address *a1, Address *a2);
|
||||
int address_configure(const Address *address, Link *link, link_netlink_message_handler_t callback, bool update, Address **ret);
|
||||
int address_remove(const Address *address, Link *link, link_netlink_message_handler_t callback);
|
||||
bool address_equal(const Address *a1, const Address *a2);
|
||||
bool address_is_ready(const Address *a);
|
||||
|
||||
int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret);
|
||||
int generate_ipv6_eui_64_address(const Link *link, struct in6_addr *ret);
|
||||
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
|
||||
|
||||
|
|
|
@ -563,6 +563,9 @@ static int dhcp_lease_lost(Link *link) {
|
|||
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
|
||||
link_dirty(link);
|
||||
|
||||
if (link->dhcp_acd)
|
||||
(void) sd_ipv4acd_stop(link->dhcp_acd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -617,26 +620,61 @@ static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
|||
return;
|
||||
}
|
||||
|
||||
static int configure_dhcpv4_duplicate_address_detection(Link *link) {
|
||||
static int dhcp4_configure_dad(Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(link->network);
|
||||
|
||||
if (!link->network->dhcp_send_decline)
|
||||
return 0;
|
||||
|
||||
if (!link->dhcp_acd) {
|
||||
r = sd_ipv4acd_new(&link->dhcp_acd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_attach_event(link->dhcp_acd, link->manager->event, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_ipv4acd_set_ifindex(link->dhcp_acd, link->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->mac);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp4_dad_update_mac(Link *link) {
|
||||
bool running;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
r = sd_ipv4acd_new(&link->network->dhcp_acd);
|
||||
if (!link->dhcp_acd)
|
||||
return 0;
|
||||
|
||||
running = sd_ipv4acd_is_running(link->dhcp_acd);
|
||||
|
||||
r = sd_ipv4acd_stop(link->dhcp_acd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_attach_event(link->network->dhcp_acd, link->manager->event, 0);
|
||||
r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->mac);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_ifindex(link->network->dhcp_acd, link->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_mac(link->network->dhcp_acd, &link->mac);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (running) {
|
||||
r = sd_ipv4acd_start(link->dhcp_acd, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -652,7 +690,7 @@ static int dhcp4_start_acd(Link *link) {
|
|||
if (!link->dhcp_lease)
|
||||
return 0;
|
||||
|
||||
(void) sd_ipv4acd_stop(link->network->dhcp_acd);
|
||||
(void) sd_ipv4acd_stop(link->dhcp_acd);
|
||||
|
||||
link->dhcp4_address_bind = false;
|
||||
|
||||
|
@ -660,15 +698,15 @@ static int dhcp4_start_acd(Link *link) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_get_address(link->network->dhcp_acd, &old);
|
||||
r = sd_ipv4acd_get_address(link->dhcp_acd, &old);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_address(link->network->dhcp_acd, &addr.in);
|
||||
r = sd_ipv4acd_set_address(link->dhcp_acd, &addr.in);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ipv4acd_set_callback(link->network->dhcp_acd, dhcp_address_on_acd, link);
|
||||
r = sd_ipv4acd_set_callback(link->dhcp_acd, dhcp_address_on_acd, link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -679,7 +717,7 @@ static int dhcp4_start_acd(Link *link) {
|
|||
log_link_debug(link, "Starting IPv4ACD client. Probing DHCPv4 address %s", strna(pretty));
|
||||
}
|
||||
|
||||
r = sd_ipv4acd_start(link->network->dhcp_acd, !in4_addr_equal(&addr.in, &old));
|
||||
r = sd_ipv4acd_start(link->dhcp_acd, !in4_addr_equal(&addr.in, &old));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -1425,11 +1463,9 @@ int dhcp4_configure(Link *link) {
|
|||
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_send_decline) {
|
||||
r = configure_dhcpv4_duplicate_address_detection(link);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m");
|
||||
}
|
||||
r = dhcp4_configure_dad(link);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m");
|
||||
|
||||
return dhcp4_set_client_identifier(link);
|
||||
}
|
||||
|
@ -1450,6 +1486,10 @@ int dhcp4_update_mac(Link *link) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp4_dad_update_mac(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -503,6 +503,7 @@ static void link_free_engines(Link *link) {
|
|||
link->dhcp6_lease = sd_dhcp6_lease_unref(link->dhcp6_lease);
|
||||
link->ndisc = sd_ndisc_unref(link->ndisc);
|
||||
link->radv = sd_radv_unref(link->radv);
|
||||
link->dhcp_acd = sd_ipv4acd_unref(link->dhcp_acd);
|
||||
}
|
||||
|
||||
static Link *link_free(Link *link) {
|
||||
|
@ -622,6 +623,12 @@ int link_stop_clients(Link *link, bool may_keep_dhcp) {
|
|||
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
|
||||
}
|
||||
|
||||
if (link->dhcp_acd) {
|
||||
k = sd_ipv4acd_stop(link->dhcp_acd);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not stop IPv4 ACD client for DHCPv4: %m");
|
||||
}
|
||||
|
||||
if (link->ipv4ll) {
|
||||
k = sd_ipv4ll_stop(link->ipv4ll);
|
||||
if (k < 0)
|
||||
|
@ -668,7 +675,7 @@ void link_enter_failed(Link *link) {
|
|||
|
||||
link_set_state(link, LINK_STATE_FAILED);
|
||||
|
||||
link_stop_clients(link, false);
|
||||
(void) link_stop_clients(link, false);
|
||||
|
||||
link_dirty(link);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "sd-dhcp-client.h"
|
||||
#include "sd-dhcp-server.h"
|
||||
#include "sd-dhcp6-client.h"
|
||||
#include "sd-ipv4acd.h"
|
||||
#include "sd-ipv4ll.h"
|
||||
#include "sd-lldp.h"
|
||||
#include "sd-ndisc.h"
|
||||
|
@ -105,6 +106,7 @@ typedef struct Link {
|
|||
uint32_t original_mtu;
|
||||
unsigned dhcp4_messages;
|
||||
unsigned dhcp4_remove_messages;
|
||||
sd_ipv4acd *dhcp_acd;
|
||||
bool dhcp4_route_failed:1;
|
||||
bool dhcp4_route_retrying:1;
|
||||
bool dhcp4_configured:1;
|
||||
|
|
|
@ -725,8 +725,10 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
|
|||
SET_FOREACH(a, addresses) {
|
||||
Address *existing_address;
|
||||
|
||||
address->in_addr.in6 = *a;
|
||||
|
||||
/* see RFC4862 section 5.5.3.e */
|
||||
r = address_get(link, AF_INET6, (union in_addr_union *) a, prefixlen, &existing_address);
|
||||
r = address_get(link, address, &existing_address);
|
||||
if (r > 0) {
|
||||
lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
|
||||
if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
|
||||
|
@ -743,8 +745,6 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
|
|||
if (address->cinfo.ifa_valid == 0)
|
||||
continue;
|
||||
|
||||
address->in_addr.in6 = *a;
|
||||
|
||||
r = ndisc_address_configure(address, link, rt);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
|
||||
|
|
|
@ -636,9 +636,6 @@ static Network *network_free(Network *network) {
|
|||
strv_free(network->dhcp6_user_class);
|
||||
strv_free(network->dhcp6_vendor_class);
|
||||
|
||||
if (network->dhcp_acd)
|
||||
sd_ipv4acd_unref(network->dhcp_acd);
|
||||
|
||||
strv_free(network->ntp);
|
||||
for (unsigned i = 0; i < network->n_dns; i++)
|
||||
in_addr_full_free(network->dns[i]);
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-device.h"
|
||||
#include "sd-ipv4acd.h"
|
||||
|
||||
#include "bridge.h"
|
||||
#include "condition.h"
|
||||
|
@ -123,7 +122,6 @@ struct Network {
|
|||
bool dhcp_send_release;
|
||||
bool dhcp_send_decline;
|
||||
DHCPUseDomains dhcp_use_domains;
|
||||
sd_ipv4acd *dhcp_acd;
|
||||
Set *dhcp_deny_listed_ip;
|
||||
Set *dhcp_allow_listed_ip;
|
||||
Set *dhcp_request_options;
|
||||
|
|
|
@ -159,8 +159,10 @@ static void test_address_equality(void) {
|
|||
assert_se(in_addr_from_string(AF_INET, "192.168.3.9", &a2->in_addr) >= 0);
|
||||
assert_se(address_equal(a1, a2));
|
||||
assert_se(in_addr_from_string(AF_INET, "192.168.3.10", &a1->in_addr_peer) >= 0);
|
||||
assert_se(address_equal(a1, a2));
|
||||
assert_se(!address_equal(a1, a2));
|
||||
assert_se(in_addr_from_string(AF_INET, "192.168.3.11", &a2->in_addr_peer) >= 0);
|
||||
assert_se(!address_equal(a1, a2));
|
||||
a2->in_addr_peer = a1->in_addr_peer;
|
||||
assert_se(address_equal(a1, a2));
|
||||
a1->prefixlen = 10;
|
||||
assert_se(!address_equal(a1, a2));
|
||||
|
@ -171,10 +173,13 @@ static void test_address_equality(void) {
|
|||
assert_se(!address_equal(a1, a2));
|
||||
|
||||
a2->family = AF_INET6;
|
||||
a1->in_addr_peer = a2->in_addr_peer = IN_ADDR_NULL;
|
||||
assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::2", &a1->in_addr) >= 0);
|
||||
assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::2", &a2->in_addr) >= 0);
|
||||
assert_se(address_equal(a1, a2));
|
||||
|
||||
a1->prefixlen = 8;
|
||||
assert_se(!address_equal(a1, a2));
|
||||
a2->prefixlen = 8;
|
||||
assert_se(address_equal(a1, a2));
|
||||
|
||||
|
|
|
@ -414,7 +414,7 @@ int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, netdev_ring_param *ring) {
|
||||
int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netdev_ring_param *ring) {
|
||||
struct ethtool_ringparam ecmd = {
|
||||
.cmd = ETHTOOL_GRINGPARAM
|
||||
};
|
||||
|
@ -543,7 +543,7 @@ static int set_features_bit(
|
|||
return found ? 0 : -ENODATA;
|
||||
}
|
||||
|
||||
int ethtool_set_features(int *ethtool_fd, const char *ifname, int *features) {
|
||||
int ethtool_set_features(int *ethtool_fd, const char *ifname, const int *features) {
|
||||
_cleanup_free_ struct ethtool_gstrings *strings = NULL;
|
||||
struct ethtool_sfeatures *sfeatures;
|
||||
struct ifreq ifr = {};
|
||||
|
@ -754,7 +754,7 @@ int ethtool_set_glinksettings(
|
|||
int *fd,
|
||||
const char *ifname,
|
||||
int autonegotiation,
|
||||
uint32_t advertise[static N_ADVERTISE],
|
||||
const uint32_t advertise[static N_ADVERTISE],
|
||||
uint64_t speed,
|
||||
Duplex duplex,
|
||||
NetDevPort port) {
|
||||
|
@ -813,7 +813,7 @@ int ethtool_set_glinksettings(
|
|||
return r;
|
||||
}
|
||||
|
||||
int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels) {
|
||||
int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *channels) {
|
||||
struct ethtool_channels ecmd = {
|
||||
.cmd = ETHTOOL_GCHANNELS
|
||||
};
|
||||
|
|
|
@ -101,12 +101,12 @@ int ethtool_get_link_info(int *ethtool_fd, const char *ifname,
|
|||
int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct ether_addr *ret);
|
||||
int ethtool_set_speed(int *ethtool_fd, const char *ifname, unsigned speed, Duplex duplex);
|
||||
int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol);
|
||||
int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, netdev_ring_param *ring);
|
||||
int ethtool_set_features(int *ethtool_fd, const char *ifname, int *features);
|
||||
int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netdev_ring_param *ring);
|
||||
int ethtool_set_features(int *ethtool_fd, const char *ifname, const int *features);
|
||||
int ethtool_set_glinksettings(int *ethtool_fd, const char *ifname,
|
||||
int autonegotiation, uint32_t advertise[static N_ADVERTISE],
|
||||
int autonegotiation, const uint32_t advertise[static N_ADVERTISE],
|
||||
uint64_t speed, Duplex duplex, NetDevPort port);
|
||||
int ethtool_set_channels(int *ethtool_fd, const char *ifname, netdev_channels *channels);
|
||||
int ethtool_set_channels(int *ethtool_fd, const char *ifname, const netdev_channels *channels);
|
||||
int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int autoneg);
|
||||
|
||||
const char *duplex_to_string(Duplex d) _const_;
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
#include <sys/prctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-login.h"
|
||||
|
||||
#include "copy.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "io-util.h"
|
||||
|
@ -152,8 +155,7 @@ int pager_open(PagerFlags flags) {
|
|||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Initialize a good charset for less. This is
|
||||
* particularly important if we output UTF-8
|
||||
/* Initialize a good charset for less. This is particularly important if we output UTF-8
|
||||
* characters. */
|
||||
less_charset = getenv("SYSTEMD_LESSCHARSET");
|
||||
if (!less_charset && is_locale_utf8())
|
||||
|
@ -164,7 +166,43 @@ int pager_open(PagerFlags flags) {
|
|||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (pager_args) {
|
||||
/* People might invoke us from sudo, don't needlessly allow less to be a way to shell out
|
||||
* privileged stuff. If the user set $SYSTEMD_PAGERSECURE, trust their configuration of the
|
||||
* pager. If they didn't, use secure mode when under euid is changed. If $SYSTEMD_PAGERSECURE
|
||||
* wasn't explicitly set, and we autodetect the need for secure mode, only use the pager we
|
||||
* know to be good. */
|
||||
int use_secure_mode = getenv_bool("SYSTEMD_PAGERSECURE");
|
||||
bool trust_pager = use_secure_mode >= 0;
|
||||
if (use_secure_mode == -ENXIO) {
|
||||
uid_t uid;
|
||||
|
||||
r = sd_pid_get_owner_uid(0, &uid);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "sd_pid_get_owner_uid() failed, enabling pager secure mode: %m");
|
||||
|
||||
use_secure_mode = r < 0 || uid != geteuid();
|
||||
|
||||
} else if (use_secure_mode < 0) {
|
||||
log_warning_errno(use_secure_mode, "Unable to parse $SYSTEMD_PAGERSECURE, assuming true: %m");
|
||||
use_secure_mode = true;
|
||||
}
|
||||
|
||||
/* We generally always set variables used by less, even if we end up using a different pager.
|
||||
* They shouldn't hurt in any case, and ideally other pagers would look at them too. */
|
||||
if (use_secure_mode)
|
||||
r = setenv("LESSSECURE", "1", 1);
|
||||
else
|
||||
r = unsetenv("LESSSECURE");
|
||||
if (r < 0) {
|
||||
log_error_errno(errno, "Failed to adjust environment variable LESSSECURE: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (trust_pager && pager_args) { /* The pager config might be set globally, and we cannot
|
||||
* know if the user adjusted it to be appropriate for the
|
||||
* secure mode. Thus, start the pager specified through
|
||||
* envvars only when $SYSTEMD_PAGERSECURE was explicitly set
|
||||
* as well. */
|
||||
r = loop_write(exe_name_pipe[1], pager_args[0], strlen(pager_args[0]) + 1, false);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to write pager name to socket: %m");
|
||||
|
@ -176,13 +214,14 @@ int pager_open(PagerFlags flags) {
|
|||
"Failed to execute '%s', using fallback pagers: %m", pager_args[0]);
|
||||
}
|
||||
|
||||
/* Debian's alternatives command for pagers is
|
||||
* called 'pager'. Note that we do not call
|
||||
* sensible-pagers here, since that is just a
|
||||
* shell script that implements a logic that
|
||||
* is similar to this one anyway, but is
|
||||
* Debian-specific. */
|
||||
/* Debian's alternatives command for pagers is called 'pager'. Note that we do not call
|
||||
* sensible-pagers here, since that is just a shell script that implements a logic that is
|
||||
* similar to this one anyway, but is Debian-specific. */
|
||||
FOREACH_STRING(exe, "pager", "less", "more") {
|
||||
/* Only less implements secure mode right now. */
|
||||
if (use_secure_mode && !streq(exe, "less"))
|
||||
continue;
|
||||
|
||||
r = loop_write(exe_name_pipe[1], exe, strlen(exe) + 1, false);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to write pager name to socket: %m");
|
||||
|
@ -193,6 +232,7 @@ int pager_open(PagerFlags flags) {
|
|||
"Failed to execute '%s', using next fallback pager: %m", exe);
|
||||
}
|
||||
|
||||
/* Our builtin is also very secure. */
|
||||
r = loop_write(exe_name_pipe[1], "(built-in)", strlen("(built-in)") + 1, false);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to write pager name to socket: %m");
|
||||
|
|
|
@ -345,6 +345,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
|
|||
.value =
|
||||
"_llseek\0"
|
||||
"close\0"
|
||||
"close_range\0"
|
||||
"dup\0"
|
||||
"dup2\0"
|
||||
"dup3\0"
|
||||
|
|
|
@ -61,6 +61,12 @@ int show_environment(int argc, char *argv[], void *userdata) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void invalid_callback(const char *p, void *userdata) {
|
||||
_cleanup_free_ char *t = cescape(p);
|
||||
|
||||
log_debug("Ignoring invalid environment assignment \"%s\".", strnull(t));
|
||||
}
|
||||
|
||||
int set_environment(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
|
@ -112,9 +118,18 @@ int import_environment(int argc, char *argv[], void *userdata) {
|
|||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
if (argc < 2)
|
||||
r = sd_bus_message_append_strv(m, environ);
|
||||
else {
|
||||
if (argc < 2) {
|
||||
_cleanup_strv_free_ char **copy = NULL;
|
||||
|
||||
copy = strv_copy(environ);
|
||||
if (!copy)
|
||||
return log_oom();
|
||||
|
||||
strv_env_clean_with_callback(copy, invalid_callback, NULL);
|
||||
|
||||
r = sd_bus_message_append_strv(m, copy);
|
||||
|
||||
} else {
|
||||
char **a, **b;
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "s");
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "util.h"
|
||||
|
||||
static void test_strv_env_delete(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
_cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL;
|
||||
|
||||
a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF");
|
||||
|
@ -30,9 +32,9 @@ static void test_strv_env_delete(void) {
|
|||
}
|
||||
|
||||
static void test_strv_env_get(void) {
|
||||
char **l;
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
l = STRV_MAKE("ONE_OR_TWO=1", "THREE=3", "ONE_OR_TWO=2", "FOUR=4");
|
||||
char **l = STRV_MAKE("ONE_OR_TWO=1", "THREE=3", "ONE_OR_TWO=2", "FOUR=4");
|
||||
|
||||
assert_se(streq(strv_env_get(l, "ONE_OR_TWO"), "2"));
|
||||
assert_se(streq(strv_env_get(l, "THREE"), "3"));
|
||||
|
@ -40,6 +42,8 @@ static void test_strv_env_get(void) {
|
|||
}
|
||||
|
||||
static void test_strv_env_unset(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
|
||||
l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES");
|
||||
|
@ -53,6 +57,8 @@ static void test_strv_env_unset(void) {
|
|||
}
|
||||
|
||||
static void test_strv_env_set(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL, **r = NULL;
|
||||
|
||||
l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES");
|
||||
|
@ -69,6 +75,8 @@ static void test_strv_env_set(void) {
|
|||
}
|
||||
|
||||
static void test_strv_env_merge(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
_cleanup_strv_free_ char **a = NULL, **b = NULL, **r = NULL;
|
||||
|
||||
a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF");
|
||||
|
@ -97,6 +105,8 @@ static void test_strv_env_merge(void) {
|
|||
}
|
||||
|
||||
static void test_env_strv_get_n(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
const char *_env[] = {
|
||||
"FOO=NO NO NO",
|
||||
"FOO=BAR BAR",
|
||||
|
@ -127,6 +137,8 @@ static void test_env_strv_get_n(void) {
|
|||
}
|
||||
|
||||
static void test_replace_env(bool braceless) {
|
||||
log_info("/* %s(braceless=%s) */", __func__, yes_no(braceless));
|
||||
|
||||
const char *env[] = {
|
||||
"FOO=BAR BAR",
|
||||
"BAR=waldo",
|
||||
|
@ -152,6 +164,8 @@ static void test_replace_env(bool braceless) {
|
|||
}
|
||||
|
||||
static void test_replace_env2(bool extended) {
|
||||
log_info("/* %s(extended=%s) */", __func__, yes_no(extended));
|
||||
|
||||
const char *env[] = {
|
||||
"FOO=foo",
|
||||
"BAR=bar",
|
||||
|
@ -180,6 +194,8 @@ static void test_replace_env2(bool extended) {
|
|||
}
|
||||
|
||||
static void test_replace_env_argv(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
const char *env[] = {
|
||||
"FOO=BAR BAR",
|
||||
"BAR=waldo",
|
||||
|
@ -230,24 +246,25 @@ static void test_replace_env_argv(void) {
|
|||
}
|
||||
|
||||
static void test_env_clean(void) {
|
||||
_cleanup_strv_free_ char **e;
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
e = strv_new("FOOBAR=WALDO",
|
||||
"FOOBAR=WALDO",
|
||||
"FOOBAR",
|
||||
"F",
|
||||
"X=",
|
||||
"F=F",
|
||||
"=",
|
||||
"=F",
|
||||
"",
|
||||
"0000=000",
|
||||
"äöüß=abcd",
|
||||
"abcd=äöüß",
|
||||
"xyz\n=xyz",
|
||||
"xyz=xyz\n",
|
||||
"another=one",
|
||||
"another=final one");
|
||||
_cleanup_strv_free_ char **e = strv_new("FOOBAR=WALDO",
|
||||
"FOOBAR=WALDO",
|
||||
"FOOBAR",
|
||||
"F",
|
||||
"X=",
|
||||
"F=F",
|
||||
"=",
|
||||
"=F",
|
||||
"",
|
||||
"0000=000",
|
||||
"äöüß=abcd",
|
||||
"abcd=äöüß",
|
||||
"xyz\n=xyz",
|
||||
"xyz=xyz\n",
|
||||
"another=one",
|
||||
"another=final one",
|
||||
"BASH_FUNC_foo%%=() { echo foo\n}");
|
||||
assert_se(e);
|
||||
assert_se(!strv_env_is_valid(e));
|
||||
assert_se(strv_env_clean(e) == e);
|
||||
|
@ -256,13 +273,17 @@ static void test_env_clean(void) {
|
|||
assert_se(streq(e[0], "FOOBAR=WALDO"));
|
||||
assert_se(streq(e[1], "X="));
|
||||
assert_se(streq(e[2], "F=F"));
|
||||
assert_se(streq(e[3], "abcd=äöüß"));
|
||||
assert_se(streq(e[4], "xyz=xyz\n"));
|
||||
assert_se(streq(e[5], "another=final one"));
|
||||
assert_se(e[6] == NULL);
|
||||
assert_se(streq(e[3], "0000=000"));
|
||||
assert_se(streq(e[4], "abcd=äöüß"));
|
||||
assert_se(streq(e[5], "xyz=xyz\n"));
|
||||
assert_se(streq(e[6], "another=final one"));
|
||||
assert_se(streq(e[7], "BASH_FUNC_foo%%=() { echo foo\n}"));
|
||||
assert_se(e[8] == NULL);
|
||||
}
|
||||
|
||||
static void test_env_name_is_valid(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(env_name_is_valid("test"));
|
||||
|
||||
assert_se(!env_name_is_valid(NULL));
|
||||
|
@ -270,11 +291,16 @@ static void test_env_name_is_valid(void) {
|
|||
assert_se(!env_name_is_valid("xxx\a"));
|
||||
assert_se(!env_name_is_valid("xxx\007b"));
|
||||
assert_se(!env_name_is_valid("\007\009"));
|
||||
assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong"));
|
||||
assert_se( env_name_is_valid("5_starting_with_a_number_is_unexpected_but_valid"));
|
||||
assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed"));
|
||||
assert_se( env_name_is_valid("BASH_FUNC_foo%%"));
|
||||
assert_se(!env_name_is_valid("with spaces%%"));
|
||||
assert_se(!env_name_is_valid("with\nnewline%%"));
|
||||
}
|
||||
|
||||
static void test_env_value_is_valid(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(env_value_is_valid(""));
|
||||
assert_se(env_value_is_valid("głąb kapuściany"));
|
||||
assert_se(env_value_is_valid("printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\""));
|
||||
|
@ -283,6 +309,8 @@ static void test_env_value_is_valid(void) {
|
|||
}
|
||||
|
||||
static void test_env_assignment_is_valid(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(env_assignment_is_valid("a="));
|
||||
assert_se(env_assignment_is_valid("b=głąb kapuściany"));
|
||||
assert_se(env_assignment_is_valid("c=\\007\\009\\011"));
|
||||
|
@ -294,9 +322,13 @@ static void test_env_assignment_is_valid(void) {
|
|||
assert_se(!env_assignment_is_valid("a b="));
|
||||
assert_se(!env_assignment_is_valid("a ="));
|
||||
assert_se(!env_assignment_is_valid(" b="));
|
||||
/* no dots or dashes: http://tldp.org/LDP/abs/html/gotchas.html */
|
||||
assert_se(!env_assignment_is_valid("a.b="));
|
||||
assert_se(!env_assignment_is_valid("a-b="));
|
||||
/* Names with dots and dashes makes those variables inaccessible as bash variables (as the syntax
|
||||
* simply does not allow such variable names, see http://tldp.org/LDP/abs/html/gotchas.html). They
|
||||
* are still valid variables according to POSIX though. */
|
||||
assert_se( env_assignment_is_valid("a.b="));
|
||||
assert_se( env_assignment_is_valid("a-b="));
|
||||
/* Those are not ASCII, so not valid according to POSIX (though zsh does allow unicode variable
|
||||
* names…). */
|
||||
assert_se(!env_assignment_is_valid("\007=głąb kapuściany"));
|
||||
assert_se(!env_assignment_is_valid("c\009=\007\009\011"));
|
||||
assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;<mock-chroot>\x07<mock-chroot>\""));
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "random-util.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "serialize.h"
|
||||
#include "string-util.h"
|
||||
#include "tests.h"
|
||||
|
@ -317,6 +318,100 @@ static void test_read_nr_open(void) {
|
|||
log_info("nr-open: %i", read_nr_open());
|
||||
}
|
||||
|
||||
static size_t validate_fds(
|
||||
bool opened,
|
||||
const int *fds,
|
||||
size_t n_fds) {
|
||||
|
||||
size_t c = 0;
|
||||
|
||||
/* Validates that fds in the specified array are one of the following three:
|
||||
*
|
||||
* 1. < 0 (test is skipped) or
|
||||
* 2. opened (if 'opened' param is true) or
|
||||
* 3. closed (if 'opened' param is false)
|
||||
*/
|
||||
|
||||
for (size_t i = 0; i < n_fds; i++) {
|
||||
if (fds[i] < 0)
|
||||
continue;
|
||||
|
||||
if (opened)
|
||||
assert_se(fcntl(fds[i], F_GETFD) >= 0);
|
||||
else
|
||||
assert_se(fcntl(fds[i], F_GETFD) < 0 && errno == EBADF);
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
return c; /* Return number of fds >= 0 in the array */
|
||||
}
|
||||
|
||||
static void test_close_all_fds(void) {
|
||||
_cleanup_free_ int *fds = NULL, *keep = NULL;
|
||||
struct rlimit rl;
|
||||
size_t n_fds, n_keep;
|
||||
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
rlimit_nofile_bump(-1);
|
||||
|
||||
assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
|
||||
assert_se(rl.rlim_cur > 10);
|
||||
|
||||
/* Try to use 5000 fds, but when we can't bump the rlimit to make that happen use the whole limit minus 10 */
|
||||
n_fds = MIN((rl.rlim_cur & ~1U) - 10U, 5000U);
|
||||
assert_se((n_fds & 1U) == 0U); /* make sure even number of fds */
|
||||
|
||||
/* Allocate the determined number of fds, always two at a time */
|
||||
assert_se(fds = new(int, n_fds));
|
||||
for (size_t i = 0; i < n_fds; i += 2)
|
||||
assert_se(pipe2(fds + i, O_CLOEXEC) >= 0);
|
||||
|
||||
/* Validate this worked */
|
||||
assert_se(validate_fds(true, fds, n_fds) == n_fds);
|
||||
|
||||
/* Randomized number of fds to keep, but at most every second */
|
||||
n_keep = (random_u64() % (n_fds / 2));
|
||||
|
||||
/* Now randomly select a number of fds from the array above to keep */
|
||||
assert_se(keep = new(int, n_keep));
|
||||
for (size_t k = 0; k < n_keep; k++) {
|
||||
for (;;) {
|
||||
size_t p;
|
||||
|
||||
p = random_u64() % n_fds;
|
||||
if (fds[p] >= 0) {
|
||||
keep[k] = TAKE_FD(fds[p]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that all fds from both arrays are still open, and test how many in each are >= 0 */
|
||||
assert_se(validate_fds(true, fds, n_fds) == n_fds - n_keep);
|
||||
assert_se(validate_fds(true, keep, n_keep) == n_keep);
|
||||
|
||||
/* Close logging fd first, so that we don't confuse it by closing its fd */
|
||||
log_close();
|
||||
log_set_open_when_needed(true);
|
||||
|
||||
/* Close all but the ones to keep */
|
||||
assert_se(close_all_fds(keep, n_keep) >= 0);
|
||||
|
||||
assert_se(validate_fds(false, fds, n_fds) == n_fds - n_keep);
|
||||
assert_se(validate_fds(true, keep, n_keep) == n_keep);
|
||||
|
||||
/* Close everything else too! */
|
||||
assert_se(close_all_fds(NULL, 0) >= 0);
|
||||
|
||||
assert_se(validate_fds(false, fds, n_fds) == n_fds - n_keep);
|
||||
assert_se(validate_fds(false, keep, n_keep) == n_keep);
|
||||
|
||||
log_set_open_when_needed(false);
|
||||
log_open();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
@ -330,6 +425,7 @@ int main(int argc, char *argv[]) {
|
|||
test_rearrange_stdio();
|
||||
test_fd_duplicate_data_fd();
|
||||
test_read_nr_open();
|
||||
test_close_all_fds();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -748,26 +748,26 @@ static void test_config_parse_pass_environ(void) {
|
|||
_cleanup_strv_free_ char **passenv = NULL;
|
||||
|
||||
r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
|
||||
"PassEnvironment", 0, "A B",
|
||||
&passenv, NULL);
|
||||
"PassEnvironment", 0, "A B",
|
||||
&passenv, NULL);
|
||||
assert_se(r >= 0);
|
||||
assert_se(strv_length(passenv) == 2);
|
||||
assert_se(streq(passenv[0], "A"));
|
||||
assert_se(streq(passenv[1], "B"));
|
||||
|
||||
r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
|
||||
"PassEnvironment", 0, "",
|
||||
&passenv, NULL);
|
||||
"PassEnvironment", 0, "",
|
||||
&passenv, NULL);
|
||||
assert_se(r >= 0);
|
||||
assert_se(strv_isempty(passenv));
|
||||
|
||||
r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
|
||||
"PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\",
|
||||
&passenv, NULL);
|
||||
"PassEnvironment", 0, "'invalid name' 'normal_name' A=1 'special_name$$' \\",
|
||||
&passenv, NULL);
|
||||
assert_se(r >= 0);
|
||||
assert_se(strv_length(passenv) == 1);
|
||||
assert_se(strv_length(passenv) == 2);
|
||||
assert_se(streq(passenv[0], "normal_name"));
|
||||
|
||||
assert_se(streq(passenv[1], "special_name$$"));
|
||||
}
|
||||
|
||||
static void test_unit_dump_config_items(void) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "conf-files.h"
|
||||
#include "conf-parser.h"
|
||||
#include "def.h"
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "ethtool-util.h"
|
||||
#include "fd-util.h"
|
||||
|
@ -241,6 +242,7 @@ bool link_config_should_reload(link_config_ctx *ctx) {
|
|||
}
|
||||
|
||||
int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
|
||||
unsigned name_assign_type = NET_NAME_UNKNOWN;
|
||||
struct ether_addr permanent_mac = {};
|
||||
unsigned short iftype = 0;
|
||||
link_config *link;
|
||||
|
@ -267,40 +269,91 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
|
|||
if (r < 0)
|
||||
log_device_debug_errno(device, r, "Failed to get permanent MAC address, ignoring: %m");
|
||||
|
||||
(void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
|
||||
|
||||
LIST_FOREACH(links, link, ctx->links) {
|
||||
if (net_match_config(link->match_mac, link->match_permanent_mac, link->match_path, link->match_driver,
|
||||
link->match_type, link->match_name, link->match_property, NULL, NULL, NULL,
|
||||
device, NULL, &permanent_mac, NULL, iftype, NULL, NULL, 0, NULL, NULL)) {
|
||||
if (link->match_name && !strv_contains(link->match_name, "*")) {
|
||||
unsigned name_assign_type = NET_NAME_UNKNOWN;
|
||||
|
||||
(void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
|
||||
|
||||
if (name_assign_type == NET_NAME_ENUM) {
|
||||
log_device_warning(device, "Config file %s applies to device based on potentially unpredictable interface name",
|
||||
link->filename);
|
||||
*ret = link;
|
||||
|
||||
return 0;
|
||||
} else if (name_assign_type == NET_NAME_RENAMED) {
|
||||
log_device_warning(device, "Config file %s matches device based on renamed interface name, ignoring",
|
||||
link->filename);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
log_device_debug(device, "Config file %s is applied", link->filename);
|
||||
if (link->match_name && !strv_contains(link->match_name, "*") && name_assign_type == NET_NAME_ENUM)
|
||||
log_device_warning(device, "Config file %s is applied to device based on potentially unpredictable interface name.",
|
||||
link->filename);
|
||||
else
|
||||
log_device_debug(device, "Config file %s is applied", link->filename);
|
||||
|
||||
*ret = link;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
*ret = NULL;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int link_config_apply_ethtool_settings(int *ethtool_fd, const link_config *config, sd_device *device) {
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
assert(ethtool_fd);
|
||||
assert(config);
|
||||
assert(device);
|
||||
|
||||
r = sd_device_get_sysname(device, &name);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(device, r, "Failed to get sysname: %m");
|
||||
|
||||
r = ethtool_set_glinksettings(ethtool_fd, name,
|
||||
config->autonegotiation, config->advertise,
|
||||
config->speed, config->duplex, config->port);
|
||||
if (r < 0) {
|
||||
if (config->port != _NET_DEV_PORT_INVALID)
|
||||
log_device_warning_errno(device, r, "Could not set port '%s', ignoring: %m", port_to_string(config->port));
|
||||
|
||||
if (!eqzero(config->advertise))
|
||||
log_device_warning_errno(device, r, "Could not set advertise mode, ignoring: %m"); /* TODO: include modes in the log message. */
|
||||
|
||||
if (config->speed) {
|
||||
unsigned speed = DIV_ROUND_UP(config->speed, 1000000);
|
||||
if (r == -EOPNOTSUPP) {
|
||||
r = ethtool_set_speed(ethtool_fd, name, speed, config->duplex);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(device, r, "Could not set speed to %uMbps, ignoring: %m", speed);
|
||||
}
|
||||
}
|
||||
|
||||
if (config->duplex != _DUP_INVALID)
|
||||
log_device_warning_errno(device, r, "Could not set duplex to %s, ignoring: %m", duplex_to_string(config->duplex));
|
||||
}
|
||||
|
||||
r = ethtool_set_wol(ethtool_fd, name, config->wol);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(device, r, "Could not set WakeOnLan to %s, ignoring: %m", wol_to_string(config->wol));
|
||||
|
||||
r = ethtool_set_features(ethtool_fd, name, config->features);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(device, r, "Could not set offload features, ignoring: %m");
|
||||
|
||||
if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
|
||||
r = ethtool_set_channels(ethtool_fd, name, &config->channels);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(device, r, "Could not set channels, ignoring: %m");
|
||||
}
|
||||
|
||||
if (config->ring.rx_pending_set || config->ring.rx_mini_pending_set || config->ring.rx_jumbo_pending_set || config->ring.tx_pending_set) {
|
||||
r = ethtool_set_nic_buffer_size(ethtool_fd, name, &config->ring);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(device, r, "Could not set ring buffer, ignoring: %m");
|
||||
}
|
||||
|
||||
if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
|
||||
r = ethtool_set_flow_control(ethtool_fd, name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(device, r, "Could not set flow control, ignoring: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) {
|
||||
unsigned addr_type;
|
||||
bool want_random = policy == MAC_ADDRESS_POLICY_RANDOM;
|
||||
|
@ -357,80 +410,41 @@ static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr
|
|||
return 1;
|
||||
}
|
||||
|
||||
int link_config_apply(link_config_ctx *ctx, link_config *config,
|
||||
sd_device *device, const char **name) {
|
||||
_cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL;
|
||||
struct ether_addr generated_mac;
|
||||
struct ether_addr *mac = NULL;
|
||||
static int link_config_apply_rtnl_settings(sd_netlink **rtnl, const link_config *config, sd_device *device) {
|
||||
struct ether_addr generated_mac, *mac = NULL;
|
||||
int ifindex, r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(config);
|
||||
assert(device);
|
||||
|
||||
r = sd_device_get_ifindex(device, &ifindex);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(device, r, "Could not find ifindex: %m");
|
||||
|
||||
if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
|
||||
if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
|
||||
mac = &generated_mac;
|
||||
} else
|
||||
mac = config->mac;
|
||||
|
||||
r = rtnl_set_link_properties(rtnl, ifindex, config->alias, mac, config->mtu);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(device, r, "Could not set Alias=, MACAddress= or MTU=, ignoring: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_config_generate_new_name(const link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) {
|
||||
unsigned name_type = NET_NAME_UNKNOWN;
|
||||
const char *new_name = NULL;
|
||||
const char *old_name;
|
||||
unsigned speed, name_type = NET_NAME_UNKNOWN;
|
||||
NamePolicy policy;
|
||||
int r, ifindex;
|
||||
int r;
|
||||
|
||||
assert(ctx);
|
||||
assert(config);
|
||||
assert(device);
|
||||
assert(name);
|
||||
|
||||
r = sd_device_get_sysname(device, &old_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name,
|
||||
config->autonegotiation, config->advertise,
|
||||
config->speed, config->duplex, config->port);
|
||||
if (r < 0) {
|
||||
|
||||
if (config->port != _NET_DEV_PORT_INVALID)
|
||||
log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
|
||||
|
||||
if (!eqzero(config->advertise))
|
||||
log_warning_errno(r, "Could not set advertise mode: %m"); /* TODO: include modes in the log message. */
|
||||
|
||||
if (config->speed) {
|
||||
speed = DIV_ROUND_UP(config->speed, 1000000);
|
||||
if (r == -EOPNOTSUPP) {
|
||||
r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not set speed of %s to %u Mbps: %m", old_name, speed);
|
||||
}
|
||||
}
|
||||
|
||||
if (config->duplex != _DUP_INVALID)
|
||||
log_warning_errno(r, "Could not set duplex of %s to %s: %m", old_name, duplex_to_string(config->duplex));
|
||||
}
|
||||
|
||||
r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
|
||||
old_name, wol_to_string(config->wol));
|
||||
|
||||
r = ethtool_set_features(&ctx->ethtool_fd, old_name, config->features);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not set offload features of %s: %m", old_name);
|
||||
|
||||
if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
|
||||
r = ethtool_set_channels(&ctx->ethtool_fd, old_name, &config->channels);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not set channels of %s: %m", old_name);
|
||||
}
|
||||
|
||||
if (config->ring.rx_pending_set || config->ring.rx_mini_pending_set || config->ring.rx_jumbo_pending_set || config->ring.tx_pending_set) {
|
||||
r = ethtool_set_nic_buffer_size(&ctx->ethtool_fd, old_name, &config->ring);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not set ring buffer of %s: %m", old_name);
|
||||
}
|
||||
|
||||
if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
|
||||
r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not set flow control of %s: %m", old_name);
|
||||
}
|
||||
|
||||
r = sd_device_get_ifindex(device, &ifindex);
|
||||
if (r < 0)
|
||||
return log_device_warning_errno(device, r, "Could not find ifindex: %m");
|
||||
assert(ret_name);
|
||||
|
||||
(void) link_unsigned_attribute(device, "name_assign_type", &name_type);
|
||||
|
||||
|
@ -482,24 +496,43 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
|
|||
break;
|
||||
}
|
||||
|
||||
if (new_name)
|
||||
if (new_name) {
|
||||
log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
|
||||
else if (config->name) {
|
||||
new_name = config->name;
|
||||
log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name);
|
||||
} else
|
||||
log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
|
||||
no_rename:
|
||||
*ret_name = new_name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
|
||||
if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
|
||||
mac = &generated_mac;
|
||||
} else
|
||||
mac = config->mac;
|
||||
if (config->name) {
|
||||
log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", config->name);
|
||||
*ret_name = config->name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
|
||||
log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
|
||||
no_rename:
|
||||
r = sd_device_get_sysname(device, ret_name);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Could not set Alias=, MACAddress= or MTU= on %s: %m", old_name);
|
||||
return log_device_error_errno(device, r, "Failed to get sysname: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_config_apply_alternative_names(sd_netlink **rtnl, const link_config *config, sd_device *device, const char *new_name) {
|
||||
_cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL;
|
||||
const char *current_name;
|
||||
int ifindex, r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(config);
|
||||
assert(device);
|
||||
|
||||
r = sd_device_get_sysname(device, ¤t_name);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(device, r, "Failed to get sysname: %m");
|
||||
|
||||
r = sd_device_get_ifindex(device, &ifindex);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(device, r, "Could not find ifindex: %m");
|
||||
|
||||
if (config->alternative_names) {
|
||||
altnames = strv_copy(config->alternative_names);
|
||||
|
@ -539,11 +572,11 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
|
|||
|
||||
if (new_name)
|
||||
strv_remove(altnames, new_name);
|
||||
strv_remove(altnames, old_name);
|
||||
strv_remove(altnames, current_name);
|
||||
|
||||
r = rtnl_get_link_alternative_names(&ctx->rtnl, ifindex, ¤t_altnames);
|
||||
r = rtnl_get_link_alternative_names(rtnl, ifindex, ¤t_altnames);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to get alternative names on %s, ignoring: %m", old_name);
|
||||
log_device_debug_errno(device, r, "Failed to get alternative names, ignoring: %m");
|
||||
|
||||
char **p;
|
||||
STRV_FOREACH(p, current_altnames)
|
||||
|
@ -551,14 +584,63 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
|
|||
|
||||
strv_uniq(altnames);
|
||||
strv_sort(altnames);
|
||||
r = rtnl_set_link_alternative_names(&ctx->rtnl, ifindex, altnames);
|
||||
if (r == -EOPNOTSUPP)
|
||||
log_debug_errno(r, "Could not set AlternativeName= or apply AlternativeNamesPolicy= on %s, ignoring: %m", old_name);
|
||||
else if (r < 0)
|
||||
return log_warning_errno(r, "Could not set AlternativeName= or apply AlternativeNamesPolicy= on %s: %m", old_name);
|
||||
r = rtnl_set_link_alternative_names(rtnl, ifindex, altnames);
|
||||
if (r < 0)
|
||||
log_device_full_errno(device, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m");
|
||||
|
||||
*name = new_name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_config_apply(link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) {
|
||||
const char *new_name;
|
||||
DeviceAction a;
|
||||
int r;
|
||||
|
||||
assert(ctx);
|
||||
assert(config);
|
||||
assert(device);
|
||||
assert(ret_name);
|
||||
|
||||
r = device_get_action(device, &a);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(device, r, "Failed to get ACTION= property: %m");
|
||||
|
||||
if (!IN_SET(a, DEVICE_ACTION_ADD, DEVICE_ACTION_BIND, DEVICE_ACTION_MOVE)) {
|
||||
log_device_debug(device, "Skipping to apply .link settings on '%s' uevent.", device_action_to_string(a));
|
||||
|
||||
r = sd_device_get_sysname(device, ret_name);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(device, r, "Failed to get sysname: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = link_config_apply_ethtool_settings(&ctx->ethtool_fd, config, device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_config_apply_rtnl_settings(&ctx->rtnl, config, device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (a == DEVICE_ACTION_MOVE) {
|
||||
log_device_debug(device, "Skipping to apply Name= and NamePolicy= on '%s' uevent.", device_action_to_string(a));
|
||||
|
||||
r = sd_device_get_sysname(device, &new_name);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(device, r, "Failed to get sysname: %m");
|
||||
} else {
|
||||
r = link_config_generate_new_name(ctx, config, device, &new_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = link_config_apply_alternative_names(&ctx->rtnl, config, device, new_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret_name = new_name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,8 +77,8 @@ int link_load_one(link_config_ctx *ctx, const char *filename);
|
|||
int link_config_load(link_config_ctx *ctx);
|
||||
bool link_config_should_reload(link_config_ctx *ctx);
|
||||
|
||||
int link_config_get(link_config_ctx *ctx, sd_device *device, struct link_config **ret);
|
||||
int link_config_apply(link_config_ctx *ctx, struct link_config *config, sd_device *device, const char **name);
|
||||
int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret);
|
||||
int link_config_apply(link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name);
|
||||
int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret);
|
||||
|
||||
const char *name_policy_to_string(NamePolicy p) _const_;
|
||||
|
|
|
@ -940,16 +940,9 @@ static void event_execute_rules_on_remove(
|
|||
(void) udev_node_remove(dev);
|
||||
}
|
||||
|
||||
static int udev_event_on_move(UdevEvent *event) {
|
||||
sd_device *dev = event->dev;
|
||||
static int udev_event_on_move(sd_device *dev) {
|
||||
int r;
|
||||
|
||||
if (sd_device_get_devnum(dev, NULL) < 0) {
|
||||
r = device_copy_properties(dev, event->dev_db_clone);
|
||||
if (r < 0)
|
||||
log_device_debug_errno(dev, r, "Failed to copy properties from cloned sd_device object, ignoring: %m");
|
||||
}
|
||||
|
||||
/* Drop previously added property */
|
||||
r = device_add_property(dev, "ID_RENAMING", NULL);
|
||||
if (r < 0)
|
||||
|
@ -1017,7 +1010,7 @@ int udev_event_execute_rules(UdevEvent *event,
|
|||
(void) udev_watch_end(event->dev_db_clone);
|
||||
|
||||
if (action == DEVICE_ACTION_MOVE) {
|
||||
r = udev_event_on_move(event);
|
||||
r = udev_event_on_move(event->dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,24 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
TEST_DESCRIPTION="UDEV ID_RENAMING property"
|
||||
IMAGE_NAME="udev-id-renaming"
|
||||
TEST_NO_NSPAWN=1
|
||||
|
||||
. $TEST_BASE_DIR/test-functions
|
||||
QEMU_TIMEOUT=300
|
||||
|
||||
test_create_image() {
|
||||
create_empty_image_rootdir
|
||||
|
||||
# Create what will eventually be our root filesystem onto an overlay
|
||||
(
|
||||
LOG_LEVEL=5
|
||||
setup_basic_environment
|
||||
mask_supporting_services
|
||||
|
||||
instmods dummy
|
||||
generate_module_dependencies
|
||||
)
|
||||
}
|
||||
|
||||
do_test "$@" 29
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
[Match]
|
||||
Name=dummy98
|
||||
|
||||
[Network]
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[Address]
|
||||
Address=100.64.0.1/32
|
||||
Peer=100.64.0.2/32
|
|
@ -1742,6 +1742,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
|||
'25-address-dad-veth-peer.network',
|
||||
'25-address-dad-veth99.network',
|
||||
'25-address-link-section.network',
|
||||
'25-address-peer-ipv4.network',
|
||||
'25-address-preferred-lifetime-zero.network',
|
||||
'25-address-static.network',
|
||||
'25-bind-carrier.network',
|
||||
|
@ -1886,6 +1887,21 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
|||
print(output)
|
||||
self.assertNotRegex(output, '192.168.100.10/24')
|
||||
|
||||
def test_address_peer_ipv4(self):
|
||||
# test for issue #17304
|
||||
copy_unit_to_networkd_unit_path('25-address-peer-ipv4.network', '12-dummy.netdev')
|
||||
|
||||
for trial in range(2):
|
||||
if trial == 0:
|
||||
start_networkd()
|
||||
else:
|
||||
restart_networkd()
|
||||
|
||||
self.wait_online(['dummy98:routable'])
|
||||
|
||||
output = check_output('ip -4 address show dev dummy98')
|
||||
self.assertIn('inet 100.64.0.1 peer 100.64.0.2/32 scope global', output)
|
||||
|
||||
@expectedFailureIfModuleIsNotAvailable('vrf')
|
||||
def test_prefix_route(self):
|
||||
copy_unit_to_networkd_unit_path('25-prefix-route-with-vrf.network', '12-dummy.netdev',
|
||||
|
|
|
@ -38,6 +38,22 @@ STATE=$(systemctl show --property=ActiveState --value sys-devices-virtual-net-lo
|
|||
rm -f /run/udev/rules.d/50-testsuite.rules
|
||||
udevadm control --reload --timeout=600
|
||||
|
||||
# test for issue #16967
|
||||
|
||||
ip link add hoge type dummy
|
||||
udevadm info --wait-for-initialization=10s /sys/devices/virtual/net/hoge
|
||||
sleep 1
|
||||
if ! systemctl status sys-devices-virtual-net-hoge.device; then exit 1; fi
|
||||
if ! systemctl status sys-subsystem-net-devices-hoge.device; then exit 1; fi
|
||||
|
||||
ip link set hoge name foobar
|
||||
udevadm info --wait-for-initialization=10s /sys/devices/virtual/net/foobar
|
||||
sleep 1
|
||||
if systemctl status sys-devices-virtual-net-hoge.device; then exit 1; fi
|
||||
if systemctl status sys-subsystem-net-devices-hoge.device; then exit 1; fi
|
||||
if ! systemctl status sys-devices-virtual-net-foobar.device; then exit 1; fi
|
||||
if ! systemctl status sys-subsystem-net-devices-foobar.device; then exit 1; fi
|
||||
|
||||
echo OK > /testok
|
||||
|
||||
exit 0
|
||||
|
|
Loading…
Reference in New Issue