Compare commits
24 Commits
c4700b257b
...
0e9f932cf0
Author | SHA1 | Date |
---|---|---|
Yu Watanabe | 0e9f932cf0 | |
Yu Watanabe | a2fbe9f3f9 | |
Yu Watanabe | 7c778cecdb | |
Yu Watanabe | 46718d344f | |
Yu Watanabe | 9295c7ae09 | |
Yu Watanabe | 41afafbf2a | |
Yu Watanabe | 9671efff78 | |
Yu Watanabe | 4f0bc2582e | |
Yu Watanabe | 3292120adf | |
Yu Watanabe | f6cc5e1c8d | |
Yu Watanabe | 590f430cac | |
Mike Yuan | 93d2d36638 | |
Lennart Poettering | 369b12375b | |
Yu Watanabe | b5ec8f77e0 | |
Lennart Poettering | 3e0a3a0259 | |
Celeste Liu | 6573f0c82c | |
Lennart Poettering | a859d0d378 | |
Lennart Poettering | db15657dfb | |
Lennart Poettering | 2aa3005ad2 | |
Lennart Poettering | 90cf998875 | |
Lennart Poettering | c8d60ae79d | |
Lennart Poettering | bfcf48b842 | |
Yu Watanabe | 5f5c5c48b9 | |
Yu Watanabe | 68fdef46a7 |
13
NEWS
13
NEWS
|
@ -2,6 +2,15 @@ systemd System and Service Manager
|
||||||
|
|
||||||
CHANGES WITH 257 in spe:
|
CHANGES WITH 257 in spe:
|
||||||
|
|
||||||
|
Incompatible changes:
|
||||||
|
|
||||||
|
* The --purge switch of systemd-tmpfiles (which was added in v256) has
|
||||||
|
been reworked: it will now only apply to tmpfiles.d/ lines marked
|
||||||
|
with the new "$" flag. This is an incompatible change, and means any
|
||||||
|
tmpfiles.d/ files which shall be used together with --purge need to
|
||||||
|
be updated accordingly. This change has been made to make it harder
|
||||||
|
to accidentally delete too many files when using --purge incorrectly.
|
||||||
|
|
||||||
Announcements of Future Feature Removals and Incompatible Changes:
|
Announcements of Future Feature Removals and Incompatible Changes:
|
||||||
|
|
||||||
* Support for automatic flushing of the nscd user/group database caches
|
* Support for automatic flushing of the nscd user/group database caches
|
||||||
|
@ -85,7 +94,7 @@ CHANGES WITH 257 in spe:
|
||||||
/usr/lib/clock-epoch, and /var/lib/systemd/timesync/clock. See
|
/usr/lib/clock-epoch, and /var/lib/systemd/timesync/clock. See
|
||||||
systemd(1) for an detailed updated description.
|
systemd(1) for an detailed updated description.
|
||||||
|
|
||||||
* Ctrl-Alt-Delete is reenabled during late shutdown, so that the user
|
* Ctrl-Alt-Delete is re-enabled during late shutdown, so that the user
|
||||||
can still initiate a reboot if the system freezes.
|
can still initiate a reboot if the system freezes.
|
||||||
|
|
||||||
* Unit option PrivateUsers=identity can be used to request a user
|
* Unit option PrivateUsers=identity can be used to request a user
|
||||||
|
@ -202,7 +211,7 @@ CHANGES WITH 257 in spe:
|
||||||
versions.
|
versions.
|
||||||
|
|
||||||
* systemd-sysupdate gained a new --transfer-source= option to set the
|
* systemd-sysupdate gained a new --transfer-source= option to set the
|
||||||
directory to which transfer sources cofigured with
|
directory to which transfer sources configured with
|
||||||
PathRelativeTo=explicit will be interpreted.
|
PathRelativeTo=explicit will be interpreted.
|
||||||
|
|
||||||
Miscellaneous:
|
Miscellaneous:
|
||||||
|
|
|
@ -310,6 +310,10 @@ mouse:bluetooth:v047dp8019:name:Expert Wireless TB Mouse:*
|
||||||
ID_INPUT_TRACKBALL=1
|
ID_INPUT_TRACKBALL=1
|
||||||
MOUSE_DPI=400@125
|
MOUSE_DPI=400@125
|
||||||
|
|
||||||
|
# Kensington SlimBlade Pro trackball (via Bluetooth)
|
||||||
|
mouse:bluetooth:v047dp80d4:name:SlimBlade Pro:*
|
||||||
|
ID_INPUT_TRACKBALL=1
|
||||||
|
|
||||||
##########################################
|
##########################################
|
||||||
# Lenovo
|
# Lenovo
|
||||||
##########################################
|
##########################################
|
||||||
|
|
|
@ -267,7 +267,8 @@
|
||||||
<term><option>kernel-identify</option> <replaceable>kernel</replaceable></term>
|
<term><option>kernel-identify</option> <replaceable>kernel</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>Takes a kernel image as argument. Checks what kind of kernel the image is. Returns
|
<listitem><para>Takes a kernel image as argument. Checks what kind of kernel the image is. Returns
|
||||||
one of <literal>uki</literal>, <literal>pe</literal>, and <literal>unknown</literal>.
|
one of <literal>uki</literal>, <literal>addon</literal>, <literal>pe</literal>, and
|
||||||
|
<literal>unknown</literal>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
|
||||||
|
@ -360,6 +361,24 @@
|
||||||
<xi:include href="version-info.xml" xpointer="v242"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v242"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--print-loader-path</option></term>
|
||||||
|
<listitem><para>This option modifies the behaviour of <command>status</command>: it shows the
|
||||||
|
absolute path to the boot loader EFI binary used for the current boot if this information is
|
||||||
|
available. Note that no attempt is made to verify whether the binary still exists.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--print-stub-path</option></term>
|
||||||
|
<listitem><para>This option modifies the behaviour of <command>status</command>: it shows the
|
||||||
|
absolute path to the UKI/stub EFI binary used for the current boot if this information is
|
||||||
|
available. Note that no attempt is made to verify whether the binary still exists.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-R</option></term>
|
<term><option>-R</option></term>
|
||||||
<term><option>--print-root-device</option></term>
|
<term><option>--print-root-device</option></term>
|
||||||
|
|
|
@ -115,7 +115,7 @@
|
||||||
result can be pre-calculated without too much effort. The <literal>.pcrsig</literal> section is not
|
result can be pre-calculated without too much effort. The <literal>.pcrsig</literal> section is not
|
||||||
included in this PCR measurement, since it is supposed to contain signatures for the output of the
|
included in this PCR measurement, since it is supposed to contain signatures for the output of the
|
||||||
measurement operation, and thus cannot also be input to it. If an UKI contains multiple profiles, only
|
measurement operation, and thus cannot also be input to it. If an UKI contains multiple profiles, only
|
||||||
the PE sections of the selected profile (and those of the base profile, except if overriden) are
|
the PE sections of the selected profile (and those of the base profile, except if overridden) are
|
||||||
measured.</para>
|
measured.</para>
|
||||||
|
|
||||||
<para>If non-zero, the selected numeric profile is measured into PCR 12.</para>
|
<para>If non-zero, the selected numeric profile is measured into PCR 12.</para>
|
||||||
|
|
|
@ -152,10 +152,11 @@
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--purge</option></term>
|
<term><option>--purge</option></term>
|
||||||
|
|
||||||
<listitem><para>If this option is passed, all files and directories marked for
|
<listitem><para>If this option is passed, all files and directories declared for
|
||||||
<emphasis>creation</emphasis> by the <filename>tmpfiles.d/</filename> files specified on the command
|
<emphasis>creation</emphasis> and marked with the <literal>$</literal> character by the
|
||||||
line will be <emphasis>deleted</emphasis>. Specifically, this acts on all files and directories
|
<filename>tmpfiles.d/</filename> files specified on the command line will be
|
||||||
marked with <varname>f</varname>, <varname>F</varname>, <varname>d</varname>, <varname>D</varname>,
|
<emphasis>deleted</emphasis>. Specifically, this acts on all files and directories marked with
|
||||||
|
<varname>f</varname>, <varname>F</varname>, <varname>d</varname>, <varname>D</varname>,
|
||||||
<varname>v</varname>, <varname>q</varname>, <varname>Q</varname>, <varname>p</varname>,
|
<varname>v</varname>, <varname>q</varname>, <varname>Q</varname>, <varname>p</varname>,
|
||||||
<varname>L</varname>, <varname>c</varname>, <varname>b</varname>, <varname>C</varname>,
|
<varname>L</varname>, <varname>c</varname>, <varname>b</varname>, <varname>C</varname>,
|
||||||
<varname>w</varname>, <varname>e</varname>. If this switch is used at least one
|
<varname>w</varname>, <varname>e</varname>. If this switch is used at least one
|
||||||
|
|
|
@ -539,6 +539,10 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
|
||||||
service, the line is silently skipped. If <literal>^</literal> and <literal>~</literal> are combined
|
service, the line is silently skipped. If <literal>^</literal> and <literal>~</literal> are combined
|
||||||
Base64 decoding is applied to the credential contents.</para>
|
Base64 decoding is applied to the credential contents.</para>
|
||||||
|
|
||||||
|
<para>If the dollar sign (<literal>$</literal>) is used, the file becomes subject to removal when
|
||||||
|
<command>systemd-tmpfiles</command> is invoked with the <option>--purge</option> switch. Lines without
|
||||||
|
this character are unaffected by that switch.</para>
|
||||||
|
|
||||||
<para>Note that for all line types that result in creation of any kind of file node
|
<para>Note that for all line types that result in creation of any kind of file node
|
||||||
(i.e. <varname>f</varname>,
|
(i.e. <varname>f</varname>,
|
||||||
<varname>d</varname>/<varname>D</varname>/<varname>v</varname>/<varname>q</varname>/<varname>Q</varname>,
|
<varname>d</varname>/<varname>D</varname>/<varname>v</varname>/<varname>q</varname>/<varname>Q</varname>,
|
||||||
|
|
|
@ -141,6 +141,12 @@
|
||||||
For example, e"string\n" is parsed as 7 characters: 6 lowercase letters and a newline.
|
For example, e"string\n" is parsed as 7 characters: 6 lowercase letters and a newline.
|
||||||
This can be useful for writing special characters when a kernel driver requires them.</para>
|
This can be useful for writing special characters when a kernel driver requires them.</para>
|
||||||
|
|
||||||
|
<para>The string can be prefixed with a lowercase i (i"string") to mark that the string or pattern
|
||||||
|
will match case-insensitively. For example, i"foo" will match
|
||||||
|
<literal>foo</literal>, <literal>FOO</literal>, <literal>FoO</literal> and so on. The prefix can be
|
||||||
|
used only for match (<literal>==</literal>) or unmatch (<literal>!=</literal>) rules, e.g.
|
||||||
|
<varname>ATTR{foo}==i"abcd"</varname>.</para>
|
||||||
|
|
||||||
<para>Please note that <constant>NUL</constant> is not allowed in either string variant.</para>
|
<para>Please note that <constant>NUL</constant> is not allowed in either string variant.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,12 @@ const char* const systemd_features =
|
||||||
" -BPF_FRAMEWORK"
|
" -BPF_FRAMEWORK"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_VMLINUX_H
|
||||||
|
" +BTF"
|
||||||
|
#else
|
||||||
|
" -BTF"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if HAVE_XKBCOMMON
|
#if HAVE_XKBCOMMON
|
||||||
" +XKBCOMMON"
|
" +XKBCOMMON"
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -145,8 +145,10 @@ int efi_get_variable(
|
||||||
int efi_get_variable_string(const char *variable, char **ret) {
|
int efi_get_variable_string(const char *variable, char **ret) {
|
||||||
_cleanup_free_ void *s = NULL;
|
_cleanup_free_ void *s = NULL;
|
||||||
size_t ss = 0;
|
size_t ss = 0;
|
||||||
int r;
|
|
||||||
char *x;
|
char *x;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(variable);
|
||||||
|
|
||||||
r = efi_get_variable(variable, NULL, &s, &ss);
|
r = efi_get_variable(variable, NULL, &s, &ss);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -156,10 +158,27 @@ int efi_get_variable_string(const char *variable, char **ret) {
|
||||||
if (!x)
|
if (!x)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (ret)
|
||||||
*ret = x;
|
*ret = x;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int efi_get_variable_path(const char *variable, char **ret) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(variable);
|
||||||
|
|
||||||
|
r = efi_get_variable_string(variable, ret);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
efi_tilt_backslashes(*ret);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static int efi_verify_variable(const char *variable, uint32_t attr, const void *value, size_t size) {
|
static int efi_verify_variable(const char *variable, uint32_t attr, const void *value, size_t size) {
|
||||||
_cleanup_free_ void *buf = NULL;
|
_cleanup_free_ void *buf = NULL;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "sd-id128.h"
|
#include "sd-id128.h"
|
||||||
|
|
||||||
#include "efivars-fundamental.h"
|
#include "efivars-fundamental.h"
|
||||||
|
#include "string-util.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
|
#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
|
|
||||||
int efi_get_variable(const char *variable, uint32_t *attribute, void **ret_value, size_t *ret_size);
|
int efi_get_variable(const char *variable, uint32_t *attribute, void **ret_value, size_t *ret_size);
|
||||||
int efi_get_variable_string(const char *variable, char **ret);
|
int efi_get_variable_string(const char *variable, char **ret);
|
||||||
|
int efi_get_variable_path(const char *variable, char **ret);
|
||||||
int efi_set_variable(const char *variable, const void *value, size_t size);
|
int efi_set_variable(const char *variable, const void *value, size_t size);
|
||||||
int efi_set_variable_string(const char *variable, const char *p);
|
int efi_set_variable_string(const char *variable, const char *p);
|
||||||
|
|
||||||
|
@ -68,6 +70,10 @@ static inline int efi_get_variable_string(const char *variable, char **ret) {
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int efi_get_variable_path(const char *variable, char **ret) {
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int efi_set_variable(const char *variable, const void *value, size_t size) {
|
static inline int efi_set_variable(const char *variable, const void *value, size_t size) {
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -100,3 +106,7 @@ static inline int systemd_efi_options_efivarfs_if_newer(char **line) {
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline char *efi_tilt_backslashes(char *s) {
|
||||||
|
return string_replace_char(s, '\\', '/');
|
||||||
|
}
|
||||||
|
|
|
@ -219,14 +219,12 @@ static int acquire_boot_count_path(
|
||||||
uint64_t left, done;
|
uint64_t left, done;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderBootCountPath), &path);
|
r = efi_get_variable_path(EFI_LOADER_VARIABLE(LoaderBootCountPath), &path);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
return -EUNATCH; /* in this case, let the caller print a message */
|
return -EUNATCH; /* in this case, let the caller print a message */
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read LoaderBootCountPath EFI variable: %m");
|
return log_error_errno(r, "Failed to read LoaderBootCountPath EFI variable: %m");
|
||||||
|
|
||||||
efi_tilt_backslashes(path);
|
|
||||||
|
|
||||||
if (!path_is_normalized(path))
|
if (!path_is_normalized(path))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Path read from LoaderBootCountPath is not normalized, refusing: %s",
|
"Path read from LoaderBootCountPath is not normalized, refusing: %s",
|
||||||
|
|
|
@ -298,12 +298,24 @@ fail:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_efi_var(const char *variable, char **ret) {
|
static int efi_get_variable_string_and_warn(const char *variable, char **ret) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = efi_get_variable_string(variable, ret);
|
r = efi_get_variable_string(variable, ret);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
log_warning_errno(r, "Failed to read EFI variable %s: %m", variable);
|
return log_warning_errno(r, "Failed to read EFI variable '%s', ignoring: %m", variable);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efi_get_variable_path_and_warn(const char *variable, char **ret) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = efi_get_variable_path(variable, ret);
|
||||||
|
if (r < 0 && r != -ENOENT)
|
||||||
|
return log_warning_errno(r, "Failed to read EFI variable '%s', ignoring: %m", variable);
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_yes_no_line(bool first, bool good, const char *name) {
|
static void print_yes_no_line(bool first, bool good, const char *name) {
|
||||||
|
@ -396,26 +408,23 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
||||||
{ EFI_STUB_FEATURE_MULTI_PROFILE_UKI, "Stub understands profile selector" },
|
{ EFI_STUB_FEATURE_MULTI_PROFILE_UKI, "Stub understands profile selector" },
|
||||||
{ EFI_STUB_FEATURE_REPORT_STUB_PARTITION, "Stub sets stub partition information" },
|
{ EFI_STUB_FEATURE_REPORT_STUB_PARTITION, "Stub sets stub partition information" },
|
||||||
};
|
};
|
||||||
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
|
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL,
|
||||||
sd_id128_t loader_part_uuid = SD_ID128_NULL;
|
*current_entry = NULL, *oneshot_entry = NULL, *default_entry = NULL;
|
||||||
uint64_t loader_features = 0, stub_features = 0;
|
uint64_t loader_features = 0, stub_features = 0;
|
||||||
Tpm2Support s;
|
Tpm2Support s;
|
||||||
int have;
|
int have;
|
||||||
|
|
||||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
|
||||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
|
||||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
|
||||||
read_efi_var(EFI_LOADER_VARIABLE(StubInfo), &stub);
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(StubInfo), &stub);
|
||||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &loader_path);
|
(void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &loader_path);
|
||||||
|
(void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE(StubImageIdentifier), &stub_path);
|
||||||
(void) efi_loader_get_features(&loader_features);
|
(void) efi_loader_get_features(&loader_features);
|
||||||
(void) efi_stub_get_features(&stub_features);
|
(void) efi_stub_get_features(&stub_features);
|
||||||
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntrySelected), ¤t_entry);
|
||||||
if (loader_path)
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &oneshot_entry);
|
||||||
efi_tilt_backslashes(loader_path);
|
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntryDefault), &default_entry);
|
||||||
|
|
||||||
k = efi_loader_get_device_part_uuid(&loader_part_uuid);
|
|
||||||
if (k < 0 && k != -ENOENT)
|
|
||||||
r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
|
|
||||||
|
|
||||||
SecureBootMode secure = efi_get_secure_boot_mode();
|
SecureBootMode secure = efi_get_secure_boot_mode();
|
||||||
printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
|
printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
|
||||||
|
@ -463,34 +472,58 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
if (loader) {
|
||||||
printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
|
printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
|
||||||
printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal());
|
printf(" Product: %s%s%s\n", ansi_highlight(), loader, ansi_normal());
|
||||||
|
|
||||||
for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
|
for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
|
||||||
print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
|
print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
|
||||||
|
|
||||||
sd_id128_t bootloader_esp_uuid;
|
sd_id128_t loader_partition_uuid;
|
||||||
bool have_bootloader_esp_uuid = efi_loader_get_device_part_uuid(&bootloader_esp_uuid) >= 0;
|
bool have_loader_partition_uuid = efi_loader_get_device_part_uuid(&loader_partition_uuid) >= 0;
|
||||||
|
|
||||||
print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP information");
|
print_yes_no_line(false, have_loader_partition_uuid, "Boot loader set ESP information");
|
||||||
if (have_bootloader_esp_uuid && !sd_id128_is_null(esp_uuid) &&
|
|
||||||
!sd_id128_equal(esp_uuid, bootloader_esp_uuid))
|
if (current_entry)
|
||||||
printf("WARNING: The boot loader reports a different ESP UUID than detected ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
|
printf("Current Entry: %s\n", current_entry);
|
||||||
SD_ID128_FORMAT_VAL(bootloader_esp_uuid),
|
if (default_entry)
|
||||||
SD_ID128_FORMAT_VAL(esp_uuid));
|
printf("Default Entry: %s\n", default_entry);
|
||||||
|
if (oneshot_entry && !streq_ptr(oneshot_entry, default_entry))
|
||||||
|
printf("OneShot Entry: %s\n", oneshot_entry);
|
||||||
|
|
||||||
|
if (have_loader_partition_uuid && !sd_id128_is_null(esp_uuid) && !sd_id128_equal(esp_uuid, loader_partition_uuid))
|
||||||
|
printf("WARNING: The boot loader reports a different partition UUID than the detected ESP ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
|
||||||
|
SD_ID128_FORMAT_VAL(loader_partition_uuid), SD_ID128_FORMAT_VAL(esp_uuid));
|
||||||
|
|
||||||
|
if (!sd_id128_is_null(loader_partition_uuid))
|
||||||
|
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||||
|
SD_ID128_FORMAT_VAL(loader_partition_uuid));
|
||||||
|
else
|
||||||
|
printf(" Partition: n/a\n");
|
||||||
|
printf(" Loader: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (stub) {
|
if (stub) {
|
||||||
printf(" Stub: %s\n", stub);
|
printf("%sCurrent Stub:%s\n", ansi_underline(), ansi_normal());
|
||||||
|
printf(" Product: %s%s%s\n", ansi_highlight(), stub, ansi_normal());
|
||||||
for (size_t i = 0; i < ELEMENTSOF(stub_flags); i++)
|
for (size_t i = 0; i < ELEMENTSOF(stub_flags); i++)
|
||||||
print_yes_no_line(i == 0, FLAGS_SET(stub_features, stub_flags[i].flag), stub_flags[i].name);
|
print_yes_no_line(i == 0, FLAGS_SET(stub_features, stub_flags[i].flag), stub_flags[i].name);
|
||||||
}
|
|
||||||
if (!sd_id128_is_null(loader_part_uuid))
|
sd_id128_t stub_partition_uuid;
|
||||||
printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
bool have_stub_partition_uuid = efi_stub_get_device_part_uuid(&stub_partition_uuid) >= 0;
|
||||||
SD_ID128_FORMAT_VAL(loader_part_uuid));
|
|
||||||
|
if (have_stub_partition_uuid && (!(!sd_id128_is_null(esp_uuid) && sd_id128_equal(esp_uuid, stub_partition_uuid)) &&
|
||||||
|
!(!sd_id128_is_null(xbootldr_uuid) && sd_id128_equal(xbootldr_uuid, stub_partition_uuid))))
|
||||||
|
printf("WARNING: The stub loader reports a different UUID than the detected ESP or XBOOTDLR partition ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR"/"SD_ID128_UUID_FORMAT_STR")!\n",
|
||||||
|
SD_ID128_FORMAT_VAL(stub_partition_uuid), SD_ID128_FORMAT_VAL(esp_uuid), SD_ID128_FORMAT_VAL(xbootldr_uuid));
|
||||||
|
if (!sd_id128_is_null(stub_partition_uuid))
|
||||||
|
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||||
|
SD_ID128_FORMAT_VAL(stub_partition_uuid));
|
||||||
else
|
else
|
||||||
printf(" ESP: n/a\n");
|
printf(" Partition: n/a\n");
|
||||||
printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
|
printf(" Stub: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(stub_path));
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
|
printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
|
||||||
have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
|
have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
|
||||||
|
|
|
@ -16,12 +16,14 @@
|
||||||
#include "build.h"
|
#include "build.h"
|
||||||
#include "devnum-util.h"
|
#include "devnum-util.h"
|
||||||
#include "dissect-image.h"
|
#include "dissect-image.h"
|
||||||
|
#include "efi-loader.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "find-esp.h"
|
#include "find-esp.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "mount-util.h"
|
#include "mount-util.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
|
#include "path-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "varlink-io.systemd.BootControl.h"
|
#include "varlink-io.systemd.BootControl.h"
|
||||||
|
@ -38,6 +40,8 @@ char *arg_esp_path = NULL;
|
||||||
char *arg_xbootldr_path = NULL;
|
char *arg_xbootldr_path = NULL;
|
||||||
bool arg_print_esp_path = false;
|
bool arg_print_esp_path = false;
|
||||||
bool arg_print_dollar_boot_path = false;
|
bool arg_print_dollar_boot_path = false;
|
||||||
|
bool arg_print_loader_path = false;
|
||||||
|
bool arg_print_stub_path = false;
|
||||||
unsigned arg_print_root_device = 0;
|
unsigned arg_print_root_device = 0;
|
||||||
bool arg_touch_variables = true;
|
bool arg_touch_variables = true;
|
||||||
bool arg_install_random_seed = true;
|
bool arg_install_random_seed = true;
|
||||||
|
@ -133,6 +137,71 @@ int acquire_xbootldr(
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int print_loader_or_stub_path(void) {
|
||||||
|
_cleanup_free_ char *p = NULL;
|
||||||
|
sd_id128_t uuid;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (arg_print_loader_path) {
|
||||||
|
r = efi_loader_get_device_part_uuid(&uuid);
|
||||||
|
if (r == -ENOENT)
|
||||||
|
return log_error_errno(r, "No loader partition UUID passed.");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Unable to determine loader partition UUID: %m");
|
||||||
|
|
||||||
|
r = efi_get_variable_path(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &p);
|
||||||
|
if (r == -ENOENT)
|
||||||
|
return log_error_errno(r, "No loader EFI binary path passed.");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Unable to determine loader EFI binary path: %m");
|
||||||
|
} else {
|
||||||
|
assert(arg_print_stub_path);
|
||||||
|
|
||||||
|
r = efi_stub_get_device_part_uuid(&uuid);
|
||||||
|
if (r == -ENOENT)
|
||||||
|
return log_error_errno(r, "No stub partition UUID passed.");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Unable to determine stub partition UUID: %m");
|
||||||
|
|
||||||
|
r = efi_get_variable_path(EFI_LOADER_VARIABLE(StubImageIdentifier), &p);
|
||||||
|
if (r == -ENOENT)
|
||||||
|
return log_error_errno(r, "No stub EFI binary path passed.");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Unable to determine stub EFI binary path: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_id128_t esp_uuid;
|
||||||
|
r = acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false,
|
||||||
|
/* ret_part= */ NULL, /* ret_pstart= */ NULL, /* ret_psize= */ NULL,
|
||||||
|
&esp_uuid, /* ret_devid= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
const char *found_path = NULL;
|
||||||
|
if (sd_id128_equal(esp_uuid, uuid))
|
||||||
|
found_path = arg_esp_path;
|
||||||
|
else if (arg_print_stub_path) { /* In case of the stub, also look for things in the xbootldr partition */
|
||||||
|
sd_id128_t xbootldr_uuid;
|
||||||
|
|
||||||
|
r = acquire_xbootldr(/* unprivileged_mode= */ false, &xbootldr_uuid, /* ret_devid= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (sd_id128_equal(xbootldr_uuid, uuid))
|
||||||
|
found_path = arg_xbootldr_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_path)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to discover partition " SD_ID128_FORMAT_STR " among mounted boot partitions.", SD_ID128_FORMAT_VAL(uuid));
|
||||||
|
|
||||||
|
_cleanup_free_ char *j = path_join(found_path, p);
|
||||||
|
if (!j)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
puts(j);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int help(int argc, char *argv[], void *userdata) {
|
static int help(int argc, char *argv[], void *userdata) {
|
||||||
_cleanup_free_ char *link = NULL;
|
_cleanup_free_ char *link = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
@ -182,6 +251,9 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||||
" Where to pick files when using --root=/--image=\n"
|
" Where to pick files when using --root=/--image=\n"
|
||||||
" -p --print-esp-path Print path to the EFI System Partition mount point\n"
|
" -p --print-esp-path Print path to the EFI System Partition mount point\n"
|
||||||
" -x --print-boot-path Print path to the $BOOT partition mount point\n"
|
" -x --print-boot-path Print path to the $BOOT partition mount point\n"
|
||||||
|
" --print-loader-path\n"
|
||||||
|
" Print path to currently booted boot loader binary\n"
|
||||||
|
" --print-stub-path Print path to currently booted unified kernel binary\n"
|
||||||
" -R --print-root-device\n"
|
" -R --print-root-device\n"
|
||||||
" Print path to the block device node backing the\n"
|
" Print path to the block device node backing the\n"
|
||||||
" root file system (returns e.g. /dev/nvme0n1p5)\n"
|
" root file system (returns e.g. /dev/nvme0n1p5)\n"
|
||||||
|
@ -235,6 +307,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_ARCH_ALL,
|
ARG_ARCH_ALL,
|
||||||
ARG_EFI_BOOT_OPTION_DESCRIPTION,
|
ARG_EFI_BOOT_OPTION_DESCRIPTION,
|
||||||
ARG_DRY_RUN,
|
ARG_DRY_RUN,
|
||||||
|
ARG_PRINT_LOADER_PATH,
|
||||||
|
ARG_PRINT_STUB_PATH,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
|
@ -250,6 +324,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "print-esp-path", no_argument, NULL, 'p' },
|
{ "print-esp-path", no_argument, NULL, 'p' },
|
||||||
{ "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
|
{ "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
|
||||||
{ "print-boot-path", no_argument, NULL, 'x' },
|
{ "print-boot-path", no_argument, NULL, 'x' },
|
||||||
|
{ "print-loader-path", no_argument, NULL, ARG_PRINT_LOADER_PATH },
|
||||||
|
{ "print-stub-path", no_argument, NULL, ARG_PRINT_STUB_PATH },
|
||||||
{ "print-root-device", no_argument, NULL, 'R' },
|
{ "print-root-device", no_argument, NULL, 'R' },
|
||||||
{ "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
|
{ "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
|
||||||
{ "random-seed", required_argument, NULL, ARG_RANDOM_SEED },
|
{ "random-seed", required_argument, NULL, ARG_RANDOM_SEED },
|
||||||
|
@ -332,6 +408,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
arg_print_dollar_boot_path = true;
|
arg_print_dollar_boot_path = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_PRINT_LOADER_PATH:
|
||||||
|
arg_print_loader_path = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_PRINT_STUB_PATH:
|
||||||
|
arg_print_stub_path = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'R':
|
case 'R':
|
||||||
arg_print_root_device++;
|
arg_print_root_device++;
|
||||||
break;
|
break;
|
||||||
|
@ -414,9 +498,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert_not_reached();
|
assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!arg_print_esp_path + !!arg_print_dollar_boot_path + (arg_print_root_device > 0) > 1)
|
if (!!arg_print_esp_path + !!arg_print_dollar_boot_path + (arg_print_root_device > 0) + arg_print_loader_path + arg_print_stub_path > 1)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"--print-esp-path/-p, --print-boot-path/-x, --print-root-device=/-R cannot be combined.");
|
"--print-esp-path/-p, --print-boot-path/-x, --print-root-device=/-R, --print-loader-path, --print-stub-path cannot be combined.");
|
||||||
|
|
||||||
if ((arg_root || arg_image) && argv[optind] && !STR_IN_SET(argv[optind], "status", "list",
|
if ((arg_root || arg_image) && argv[optind] && !STR_IN_SET(argv[optind], "status", "list",
|
||||||
"install", "update", "remove", "is-installed", "random-seed", "unlink", "cleanup"))
|
"install", "update", "remove", "is-installed", "random-seed", "unlink", "cleanup"))
|
||||||
|
@ -541,6 +625,9 @@ static int run(int argc, char *argv[]) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg_print_loader_path || arg_print_stub_path)
|
||||||
|
return print_loader_or_stub_path();
|
||||||
|
|
||||||
/* Open up and mount the image */
|
/* Open up and mount the image */
|
||||||
if (arg_image) {
|
if (arg_image) {
|
||||||
assert(!arg_root);
|
assert(!arg_root);
|
||||||
|
|
|
@ -1046,7 +1046,6 @@ static int process_socket(int fd) {
|
||||||
_cleanup_close_ int input_fd = -EBADF, mount_tree_fd = -EBADF;
|
_cleanup_close_ int input_fd = -EBADF, mount_tree_fd = -EBADF;
|
||||||
Context context = {};
|
Context context = {};
|
||||||
struct iovec_wrapper iovw = {};
|
struct iovec_wrapper iovw = {};
|
||||||
struct iovec iovec;
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -1063,8 +1062,7 @@ static int process_socket(int fd) {
|
||||||
.msg_controllen = sizeof(control),
|
.msg_controllen = sizeof(control),
|
||||||
.msg_iovlen = 1,
|
.msg_iovlen = 1,
|
||||||
};
|
};
|
||||||
ssize_t n;
|
ssize_t n, l;
|
||||||
ssize_t l;
|
|
||||||
|
|
||||||
l = next_datagram_size_fd(fd);
|
l = next_datagram_size_fd(fd);
|
||||||
if (l < 0) {
|
if (l < 0) {
|
||||||
|
@ -1072,8 +1070,10 @@ static int process_socket(int fd) {
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
iovec.iov_len = l;
|
_cleanup_(iovec_done) struct iovec iovec = {
|
||||||
iovec.iov_base = malloc(l + 1);
|
.iov_len = l,
|
||||||
|
.iov_base = malloc(l + 1),
|
||||||
|
};
|
||||||
if (!iovec.iov_base) {
|
if (!iovec.iov_base) {
|
||||||
r = log_oom();
|
r = log_oom();
|
||||||
goto finish;
|
goto finish;
|
||||||
|
@ -1083,7 +1083,6 @@ static int process_socket(int fd) {
|
||||||
|
|
||||||
n = recvmsg_safe(fd, &mh, MSG_CMSG_CLOEXEC);
|
n = recvmsg_safe(fd, &mh, MSG_CMSG_CLOEXEC);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
free(iovec.iov_base);
|
|
||||||
r = log_error_errno(n, "Failed to receive datagram: %m");
|
r = log_error_errno(n, "Failed to receive datagram: %m");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
@ -1093,8 +1092,6 @@ static int process_socket(int fd) {
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
struct cmsghdr *found;
|
struct cmsghdr *found;
|
||||||
|
|
||||||
free(iovec.iov_base);
|
|
||||||
|
|
||||||
found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int) * 2));
|
found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int) * 2));
|
||||||
if (found) {
|
if (found) {
|
||||||
int fds[2] = EBADF_PAIR;
|
int fds[2] = EBADF_PAIR;
|
||||||
|
@ -1134,6 +1131,8 @@ static int process_socket(int fd) {
|
||||||
r = iovw_put(&iovw, iovec.iov_base, iovec.iov_len);
|
r = iovw_put(&iovw, iovec.iov_base, iovec.iov_len);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
TAKE_STRUCT(iovec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure we got all data we really need */
|
/* Make sure we got all data we really need */
|
||||||
|
|
|
@ -221,7 +221,7 @@ int link_set_ipv6ll_stable_secret(Link *link) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return sysctl_write_ip_property(AF_INET6, link->ifname, "stable_secret",
|
return sysctl_write_ip_property(AF_INET6, link->ifname, "stable_secret",
|
||||||
IN6_ADDR_TO_STRING(&a), &link->manager->sysctl_shadow);
|
IN6_ADDR_TO_STRING(&a), manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_set_ipv6ll_addrgen_mode(Link *link, IPv6LinkLocalAddressGenMode mode) {
|
int link_set_ipv6ll_addrgen_mode(Link *link, IPv6LinkLocalAddressGenMode mode) {
|
||||||
|
@ -232,7 +232,7 @@ int link_set_ipv6ll_addrgen_mode(Link *link, IPv6LinkLocalAddressGenMode mode) {
|
||||||
if (mode == link->ipv6ll_address_gen_mode)
|
if (mode == link->ipv6ll_address_gen_mode)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "addr_gen_mode", mode, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "addr_gen_mode", mode, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
|
static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
|
||||||
|
|
|
@ -624,8 +624,6 @@ Manager* manager_free(Manager *m) {
|
||||||
HASHMAP_FOREACH(link, m->links_by_index)
|
HASHMAP_FOREACH(link, m->links_by_index)
|
||||||
(void) link_stop_engines(link, true);
|
(void) link_stop_engines(link, true);
|
||||||
|
|
||||||
hashmap_free(m->sysctl_shadow);
|
|
||||||
|
|
||||||
m->request_queue = ordered_set_free(m->request_queue);
|
m->request_queue = ordered_set_free(m->request_queue);
|
||||||
m->remove_request_queue = ordered_set_free(m->remove_request_queue);
|
m->remove_request_queue = ordered_set_free(m->remove_request_queue);
|
||||||
|
|
||||||
|
|
|
@ -987,7 +987,7 @@ static int ndisc_router_process_reachable_time(Link *link, sd_ndisc_router *rt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the reachable time for Neighbor Solicitations. */
|
/* Set the reachable time for Neighbor Solicitations. */
|
||||||
r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "base_reachable_time_ms", (uint32_t) msec, &link->manager->sysctl_shadow);
|
r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "base_reachable_time_ms", (uint32_t) msec, manager_get_sysctl_shadow(link->manager));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_link_warning_errno(link, r, "Failed to apply neighbor reachable time (%"PRIu64"), ignoring: %m", msec);
|
log_link_warning_errno(link, r, "Failed to apply neighbor reachable time (%"PRIu64"), ignoring: %m", msec);
|
||||||
|
|
||||||
|
@ -1021,7 +1021,7 @@ static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the retransmission time for Neighbor Solicitations. */
|
/* Set the retransmission time for Neighbor Solicitations. */
|
||||||
r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", (uint32_t) msec, &link->manager->sysctl_shadow);
|
r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", (uint32_t) msec, manager_get_sysctl_shadow(link->manager));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_link_warning_errno(link, r, "Failed to apply neighbor retransmission time (%"PRIu64"), ignoring: %m", msec);
|
log_link_warning_errno(link, r, "Failed to apply neighbor retransmission time (%"PRIu64"), ignoring: %m", msec);
|
||||||
|
|
||||||
|
@ -1057,7 +1057,7 @@ static int ndisc_router_process_hop_limit(Link *link, sd_ndisc_router *rt) {
|
||||||
if (hop_limit <= 0)
|
if (hop_limit <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "hop_limit", (uint32_t) hop_limit, &link->manager->sysctl_shadow);
|
r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "hop_limit", (uint32_t) hop_limit, manager_get_sysctl_shadow(link->manager));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_link_warning_errno(link, r, "Failed to apply hop_limit (%u), ignoring: %m", hop_limit);
|
log_link_warning_errno(link, r, "Failed to apply hop_limit (%u), ignoring: %m", hop_limit);
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,7 @@ void sysctl_remove_monitor(Manager *manager) {
|
||||||
manager->sysctl_link = bpf_link_free(manager->sysctl_link);
|
manager->sysctl_link = bpf_link_free(manager->sysctl_link);
|
||||||
manager->sysctl_skel = sysctl_monitor_bpf_free(manager->sysctl_skel);
|
manager->sysctl_skel = sysctl_monitor_bpf_free(manager->sysctl_skel);
|
||||||
manager->cgroup_fd = safe_close(manager->cgroup_fd);
|
manager->cgroup_fd = safe_close(manager->cgroup_fd);
|
||||||
|
manager->sysctl_shadow = hashmap_free(manager->sysctl_shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sysctl_clear_link_shadows(Link *link) {
|
int sysctl_clear_link_shadows(Link *link) {
|
||||||
|
@ -195,6 +196,14 @@ int sysctl_clear_link_shadows(Link *link) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Hashmap** manager_get_sysctl_shadow(Manager *manager) {
|
||||||
|
#if HAVE_VMLINUX_H
|
||||||
|
return &ASSERT_PTR(manager)->sysctl_shadow;
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void manager_set_ip_forwarding(Manager *manager, int family) {
|
static void manager_set_ip_forwarding(Manager *manager, int family) {
|
||||||
int r, t;
|
int r, t;
|
||||||
|
|
||||||
|
@ -209,13 +218,13 @@ static void manager_set_ip_forwarding(Manager *manager, int family) {
|
||||||
return; /* keep */
|
return; /* keep */
|
||||||
|
|
||||||
/* First, set the default value. */
|
/* First, set the default value. */
|
||||||
r = sysctl_write_ip_property_boolean(family, "default", "forwarding", t, &manager->sysctl_shadow);
|
r = sysctl_write_ip_property_boolean(family, "default", "forwarding", t, manager_get_sysctl_shadow(manager));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to %s the default %s forwarding: %m",
|
log_warning_errno(r, "Failed to %s the default %s forwarding: %m",
|
||||||
enable_disable(t), af_to_ipv4_ipv6(family));
|
enable_disable(t), af_to_ipv4_ipv6(family));
|
||||||
|
|
||||||
/* Then, set the value to all interfaces. */
|
/* Then, set the value to all interfaces. */
|
||||||
r = sysctl_write_ip_property_boolean(family, "all", "forwarding", t, &manager->sysctl_shadow);
|
r = sysctl_write_ip_property_boolean(family, "all", "forwarding", t, manager_get_sysctl_shadow(manager));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to %s %s forwarding for all interfaces: %m",
|
log_warning_errno(r, "Failed to %s %s forwarding for all interfaces: %m",
|
||||||
enable_disable(t), af_to_ipv4_ipv6(family));
|
enable_disable(t), af_to_ipv4_ipv6(family));
|
||||||
|
@ -260,7 +269,7 @@ static int link_update_ipv6_sysctl(Link *link) {
|
||||||
if (!link_ipv6_enabled(link))
|
if (!link_ipv6_enabled(link))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_proxy_arp(Link *link) {
|
static int link_set_proxy_arp(Link *link) {
|
||||||
|
@ -273,7 +282,7 @@ static int link_set_proxy_arp(Link *link) {
|
||||||
if (link->network->proxy_arp < 0)
|
if (link->network->proxy_arp < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_proxy_arp_pvlan(Link *link) {
|
static int link_set_proxy_arp_pvlan(Link *link) {
|
||||||
|
@ -286,7 +295,7 @@ static int link_set_proxy_arp_pvlan(Link *link) {
|
||||||
if (link->network->proxy_arp_pvlan < 0)
|
if (link->network->proxy_arp_pvlan < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp_pvlan", link->network->proxy_arp_pvlan > 0, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp_pvlan", link->network->proxy_arp_pvlan > 0, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_get_ip_forwarding(Link *link, int family) {
|
int link_get_ip_forwarding(Link *link, int family) {
|
||||||
|
@ -328,7 +337,7 @@ static int link_set_ip_forwarding_impl(Link *link, int family) {
|
||||||
if (t < 0)
|
if (t < 0)
|
||||||
return 0; /* keep */
|
return 0; /* keep */
|
||||||
|
|
||||||
r = sysctl_write_ip_property_boolean(family, link->ifname, "forwarding", t, &link->manager->sysctl_shadow);
|
r = sysctl_write_ip_property_boolean(family, link->ifname, "forwarding", t, manager_get_sysctl_shadow(link->manager));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "Failed to %s %s forwarding, ignoring: %m",
|
return log_link_warning_errno(link, r, "Failed to %s %s forwarding, ignoring: %m",
|
||||||
enable_disable(t), af_to_ipv4_ipv6(family));
|
enable_disable(t), af_to_ipv4_ipv6(family));
|
||||||
|
@ -405,7 +414,7 @@ static int link_set_ipv4_rp_filter(Link *link) {
|
||||||
if (link->network->ipv4_rp_filter < 0)
|
if (link->network->ipv4_rp_filter < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property_int(AF_INET, link->ifname, "rp_filter", link->network->ipv4_rp_filter, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_int(AF_INET, link->ifname, "rp_filter", link->network->ipv4_rp_filter, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_ipv6_privacy_extensions(Link *link) {
|
static int link_set_ipv6_privacy_extensions(Link *link) {
|
||||||
|
@ -425,7 +434,7 @@ static int link_set_ipv6_privacy_extensions(Link *link) {
|
||||||
if (val == IPV6_PRIVACY_EXTENSIONS_KERNEL)
|
if (val == IPV6_PRIVACY_EXTENSIONS_KERNEL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) val, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) val, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_ipv6_accept_ra(Link *link) {
|
static int link_set_ipv6_accept_ra(Link *link) {
|
||||||
|
@ -435,7 +444,7 @@ static int link_set_ipv6_accept_ra(Link *link) {
|
||||||
if (!link_is_configured_for_family(link, AF_INET6))
|
if (!link_is_configured_for_family(link, AF_INET6))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0", &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0", manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_ipv6_dad_transmits(Link *link) {
|
static int link_set_ipv6_dad_transmits(Link *link) {
|
||||||
|
@ -448,7 +457,7 @@ static int link_set_ipv6_dad_transmits(Link *link) {
|
||||||
if (link->network->ipv6_dad_transmits < 0)
|
if (link->network->ipv6_dad_transmits < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_ipv6_hop_limit(Link *link) {
|
static int link_set_ipv6_hop_limit(Link *link) {
|
||||||
|
@ -461,7 +470,7 @@ static int link_set_ipv6_hop_limit(Link *link) {
|
||||||
if (link->network->ipv6_hop_limit <= 0)
|
if (link->network->ipv6_hop_limit <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_ipv6_retransmission_time(Link *link) {
|
static int link_set_ipv6_retransmission_time(Link *link) {
|
||||||
|
@ -480,7 +489,7 @@ static int link_set_ipv6_retransmission_time(Link *link) {
|
||||||
if (retrans_time_ms <= 0 || retrans_time_ms > UINT32_MAX)
|
if (retrans_time_ms <= 0 || retrans_time_ms > UINT32_MAX)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", retrans_time_ms, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", retrans_time_ms, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_ipv6_proxy_ndp(Link *link) {
|
static int link_set_ipv6_proxy_ndp(Link *link) {
|
||||||
|
@ -497,7 +506,7 @@ static int link_set_ipv6_proxy_ndp(Link *link) {
|
||||||
else
|
else
|
||||||
v = !set_isempty(link->network->ipv6_proxy_ndp_addresses);
|
v = !set_isempty(link->network->ipv6_proxy_ndp_addresses);
|
||||||
|
|
||||||
return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_set_ipv6_mtu(Link *link, int log_level) {
|
int link_set_ipv6_mtu(Link *link, int log_level) {
|
||||||
|
@ -525,7 +534,7 @@ int link_set_ipv6_mtu(Link *link, int log_level) {
|
||||||
mtu = link->mtu;
|
mtu = link->mtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_ipv4_accept_local(Link *link) {
|
static int link_set_ipv4_accept_local(Link *link) {
|
||||||
|
@ -538,7 +547,7 @@ static int link_set_ipv4_accept_local(Link *link) {
|
||||||
if (link->network->ipv4_accept_local < 0)
|
if (link->network->ipv4_accept_local < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local > 0, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local > 0, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_ipv4_route_localnet(Link *link) {
|
static int link_set_ipv4_route_localnet(Link *link) {
|
||||||
|
@ -551,7 +560,7 @@ static int link_set_ipv4_route_localnet(Link *link) {
|
||||||
if (link->network->ipv4_route_localnet < 0)
|
if (link->network->ipv4_route_localnet < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_set_ipv4_promote_secondaries(Link *link) {
|
static int link_set_ipv4_promote_secondaries(Link *link) {
|
||||||
|
@ -566,7 +575,7 @@ static int link_set_ipv4_promote_secondaries(Link *link) {
|
||||||
* otherwise. The way systemd-networkd works is that the new IP of a lease is added as a
|
* otherwise. The way systemd-networkd works is that the new IP of a lease is added as a
|
||||||
* secondary IP and when the primary one expires it relies on the kernel to promote the
|
* secondary IP and when the primary one expires it relies on the kernel to promote the
|
||||||
* secondary IP. See also https://github.com/systemd/systemd/issues/7163 */
|
* secondary IP. See also https://github.com/systemd/systemd/issues/7163 */
|
||||||
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "promote_secondaries", true, &link->manager->sysctl_shadow);
|
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "promote_secondaries", true, manager_get_sysctl_shadow(link->manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_set_sysctl(Link *link) {
|
int link_set_sysctl(Link *link) {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
|
#include "hashmap.h"
|
||||||
|
|
||||||
typedef struct Link Link;
|
typedef struct Link Link;
|
||||||
typedef struct Manager Manager;
|
typedef struct Manager Manager;
|
||||||
|
@ -37,6 +38,8 @@ static inline void sysctl_remove_monitor(Manager *manager) { }
|
||||||
static inline int sysctl_clear_link_shadows(Link *link) { return 0; }
|
static inline int sysctl_clear_link_shadows(Link *link) { return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Hashmap** manager_get_sysctl_shadow(Manager *manager);
|
||||||
|
|
||||||
void manager_set_sysctl(Manager *manager);
|
void manager_set_sysctl(Manager *manager);
|
||||||
|
|
||||||
int link_get_ip_forwarding(Link *link, int family);
|
int link_get_ip_forwarding(Link *link, int family);
|
||||||
|
|
|
@ -5602,7 +5602,7 @@ static int run_container(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: we do not use SD_EVENT_SIGNAL_PROCMASK or sd_event_set_signal_exit(), since we want the
|
/* Note: we do not use SD_EVENT_SIGNAL_PROCMASK or sd_event_set_signal_exit(), since we want the
|
||||||
* signals to be block continously, even if we destroy the event loop and allocate a new one on
|
* signals to be block continuously, even if we destroy the event loop and allocate a new one on
|
||||||
* container reboot. */
|
* container reboot. */
|
||||||
|
|
||||||
if (arg_kill_signal > 0) {
|
if (arg_kill_signal > 0) {
|
||||||
|
|
|
@ -66,9 +66,5 @@ static inline bool efi_has_tpm2(void) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline char *efi_tilt_backslashes(char *s) {
|
|
||||||
return string_replace_char(s, '\\', '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
sd_id128_t efi_guid_to_id128(const void *guid);
|
sd_id128_t efi_guid_to_id128(const void *guid);
|
||||||
void efi_id128_to_guid(sd_id128_t id, void *ret_guid);
|
void efi_id128_to_guid(sd_id128_t id, void *ret_guid);
|
||||||
|
|
|
@ -61,30 +61,19 @@ int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int efi_loader_get_device_part_uuid(sd_id128_t *ret) {
|
static int get_device_part_uuid(const char *variable, sd_id128_t *ret) {
|
||||||
_cleanup_free_ char *p = NULL;
|
|
||||||
int r;
|
|
||||||
unsigned parsed[16];
|
|
||||||
|
|
||||||
if (!is_efi_boot())
|
if (!is_efi_boot())
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderDevicePartUUID), &p);
|
return efi_get_variable_id128(variable, ret);
|
||||||
if (r < 0)
|
}
|
||||||
return r;
|
|
||||||
|
|
||||||
if (sscanf(p, SD_ID128_UUID_FORMAT_STR,
|
int efi_loader_get_device_part_uuid(sd_id128_t *ret) {
|
||||||
&parsed[0], &parsed[1], &parsed[2], &parsed[3],
|
return get_device_part_uuid(EFI_LOADER_VARIABLE(LoaderDevicePartUUID), ret);
|
||||||
&parsed[4], &parsed[5], &parsed[6], &parsed[7],
|
}
|
||||||
&parsed[8], &parsed[9], &parsed[10], &parsed[11],
|
|
||||||
&parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
if (ret)
|
int efi_stub_get_device_part_uuid(sd_id128_t *ret) {
|
||||||
for (unsigned i = 0; i < ELEMENTSOF(parsed); i++)
|
return get_device_part_uuid(EFI_LOADER_VARIABLE(StubDevicePartUUID), ret);
|
||||||
ret->bytes[i] = parsed[i];
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int efi_loader_get_entries(char ***ret) {
|
int efi_loader_get_entries(char ***ret) {
|
||||||
|
@ -353,6 +342,22 @@ int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int efi_get_variable_id128(const char *variable, sd_id128_t *ret) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(variable);
|
||||||
|
|
||||||
|
/* This is placed here (rather than in basic/efivars.c) because code in basic/ is not allowed to link
|
||||||
|
* against libsystemd.so */
|
||||||
|
|
||||||
|
_cleanup_free_ char *p = NULL;
|
||||||
|
r = efi_get_variable_string(variable, &p);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return sd_id128_from_string(p, ret);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool efi_loader_entry_name_valid(const char *s) {
|
bool efi_loader_entry_name_valid(const char *s) {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#if ENABLE_EFI
|
#if ENABLE_EFI
|
||||||
|
|
||||||
int efi_loader_get_device_part_uuid(sd_id128_t *ret);
|
int efi_loader_get_device_part_uuid(sd_id128_t *ret);
|
||||||
|
int efi_stub_get_device_part_uuid(sd_id128_t *ret);
|
||||||
int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader);
|
int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader);
|
||||||
|
|
||||||
int efi_loader_get_entries(char ***ret);
|
int efi_loader_get_entries(char ***ret);
|
||||||
|
@ -23,6 +24,8 @@ int efi_measured_uki(int log_level);
|
||||||
int efi_loader_get_config_timeout_one_shot(usec_t *ret);
|
int efi_loader_get_config_timeout_one_shot(usec_t *ret);
|
||||||
int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat);
|
int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat);
|
||||||
|
|
||||||
|
int efi_get_variable_id128(const char *variable, sd_id128_t *ret);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int efi_loader_get_device_part_uuid(sd_id128_t *u) {
|
static inline int efi_loader_get_device_part_uuid(sd_id128_t *u) {
|
||||||
|
@ -58,6 +61,10 @@ static inline int efi_loader_update_entry_one_shot_cache(char **cache, struct st
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int efi_get_variable_id128(const char *variable, sd_id128_t *ret) {
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool efi_loader_entry_name_valid(const char *s);
|
bool efi_loader_entry_name_valid(const char *s);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
static const char * const kernel_image_type_table[_KERNEL_IMAGE_TYPE_MAX] = {
|
static const char * const kernel_image_type_table[_KERNEL_IMAGE_TYPE_MAX] = {
|
||||||
[KERNEL_IMAGE_TYPE_UNKNOWN] = "unknown",
|
[KERNEL_IMAGE_TYPE_UNKNOWN] = "unknown",
|
||||||
[KERNEL_IMAGE_TYPE_UKI] = "uki",
|
[KERNEL_IMAGE_TYPE_UKI] = "uki",
|
||||||
|
[KERNEL_IMAGE_TYPE_ADDON] = "addon",
|
||||||
[KERNEL_IMAGE_TYPE_PE] = "pe",
|
[KERNEL_IMAGE_TYPE_PE] = "pe",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -159,6 +160,16 @@ int inspect_kernel(
|
||||||
|
|
||||||
t = KERNEL_IMAGE_TYPE_UKI;
|
t = KERNEL_IMAGE_TYPE_UKI;
|
||||||
goto done;
|
goto done;
|
||||||
|
} else if (pe_is_addon(pe_header, sections)) {
|
||||||
|
r = inspect_uki(fd, pe_header, sections, ret_cmdline, ret_uname, /* ret_pretty_name= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (ret_pretty_name)
|
||||||
|
*ret_pretty_name = NULL;
|
||||||
|
|
||||||
|
t = KERNEL_IMAGE_TYPE_ADDON;
|
||||||
|
goto done;
|
||||||
} else
|
} else
|
||||||
t = KERNEL_IMAGE_TYPE_PE;
|
t = KERNEL_IMAGE_TYPE_PE;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
typedef enum KernelImageType {
|
typedef enum KernelImageType {
|
||||||
KERNEL_IMAGE_TYPE_UNKNOWN,
|
KERNEL_IMAGE_TYPE_UNKNOWN,
|
||||||
KERNEL_IMAGE_TYPE_UKI,
|
KERNEL_IMAGE_TYPE_UKI,
|
||||||
|
KERNEL_IMAGE_TYPE_ADDON,
|
||||||
KERNEL_IMAGE_TYPE_PE,
|
KERNEL_IMAGE_TYPE_PE,
|
||||||
_KERNEL_IMAGE_TYPE_MAX,
|
_KERNEL_IMAGE_TYPE_MAX,
|
||||||
_KERNEL_IMAGE_TYPE_INVALID = -EINVAL,
|
_KERNEL_IMAGE_TYPE_INVALID = -EINVAL,
|
||||||
|
|
|
@ -170,6 +170,8 @@ typedef struct Item {
|
||||||
|
|
||||||
bool try_replace:1;
|
bool try_replace:1;
|
||||||
|
|
||||||
|
bool purge:1;
|
||||||
|
|
||||||
OperationMask done;
|
OperationMask done;
|
||||||
} Item;
|
} Item;
|
||||||
|
|
||||||
|
@ -3046,6 +3048,9 @@ static int purge_item(Context *c, Item *i) {
|
||||||
if (!needs_purge(i->type))
|
if (!needs_purge(i->type))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!i->purge)
|
||||||
|
return 0;
|
||||||
|
|
||||||
log_debug("Running purge action for entry %c %s", (char) i->type, i->path);
|
log_debug("Running purge action for entry %c %s", (char) i->type, i->path);
|
||||||
|
|
||||||
if (needs_glob(i->type))
|
if (needs_glob(i->type))
|
||||||
|
@ -3602,7 +3607,7 @@ static int parse_line(
|
||||||
ItemArray *existing;
|
ItemArray *existing;
|
||||||
OrderedHashmap *h;
|
OrderedHashmap *h;
|
||||||
bool append_or_force = false, boot = false, allow_failure = false, try_replace = false,
|
bool append_or_force = false, boot = false, allow_failure = false, try_replace = false,
|
||||||
unbase64 = false, from_cred = false, missing_user_or_group = false;
|
unbase64 = false, from_cred = false, missing_user_or_group = false, purge = false;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(fname);
|
assert(fname);
|
||||||
|
@ -3668,6 +3673,8 @@ static int parse_line(
|
||||||
unbase64 = true;
|
unbase64 = true;
|
||||||
else if (action[pos] == '^' && !from_cred)
|
else if (action[pos] == '^' && !from_cred)
|
||||||
from_cred = true;
|
from_cred = true;
|
||||||
|
else if (action[pos] == '$' && !purge)
|
||||||
|
purge = true;
|
||||||
else {
|
else {
|
||||||
*invalid_config = true;
|
*invalid_config = true;
|
||||||
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
|
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
|
||||||
|
@ -3684,6 +3691,7 @@ static int parse_line(
|
||||||
i.append_or_force = append_or_force;
|
i.append_or_force = append_or_force;
|
||||||
i.allow_failure = allow_failure;
|
i.allow_failure = allow_failure;
|
||||||
i.try_replace = try_replace;
|
i.try_replace = try_replace;
|
||||||
|
i.purge = purge;
|
||||||
|
|
||||||
r = specifier_printf(path, PATH_MAX-1, specifier_table, arg_root, NULL, &i.path);
|
r = specifier_printf(path, PATH_MAX-1, specifier_table, arg_root, NULL, &i.path);
|
||||||
if (ERRNO_IS_NOINFO(r))
|
if (ERRNO_IS_NOINFO(r))
|
||||||
|
@ -3838,6 +3846,12 @@ static int parse_line(
|
||||||
"Unknown command type '%c'.", (char) i.type);
|
"Unknown command type '%c'.", (char) i.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i.purge && !needs_purge(i.type)) {
|
||||||
|
*invalid_config = true;
|
||||||
|
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
|
||||||
|
"Purge flag '$' combined with line type '%c' which does not support purging.", (char) i.type);
|
||||||
|
}
|
||||||
|
|
||||||
if (!should_include_path(i.path))
|
if (!should_include_path(i.path))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
int r;
|
int r;
|
||||||
char *value = UINT_TO_PTR(0x12345678U);
|
char *value = UINT_TO_PTR(0x12345678U);
|
||||||
char *endpos = UINT_TO_PTR(0x87654321U);
|
char *endpos = UINT_TO_PTR(0x87654321U);
|
||||||
|
bool is_case_sensitive;
|
||||||
|
|
||||||
fuzz_setup_logging();
|
fuzz_setup_logging();
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
memcpy(str, data, size);
|
memcpy(str, data, size);
|
||||||
str[size] = '\0';
|
str[size] = '\0';
|
||||||
|
|
||||||
r = udev_rule_parse_value(str, &value, &endpos);
|
r = udev_rule_parse_value(str, &value, &endpos, &is_case_sensitive);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
/* not modified on failure */
|
/* not modified on failure */
|
||||||
assert_se(value == UINT_TO_PTR(0x12345678U));
|
assert_se(value == UINT_TO_PTR(0x12345678U));
|
||||||
|
|
|
@ -4,15 +4,16 @@
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "udev-rules.h"
|
#include "udev-rules.h"
|
||||||
|
|
||||||
static void test_udev_rule_parse_value_one(const char *in, const char *expected_value, int expected_retval) {
|
static void test_udev_rule_parse_value_one(const char *in, const char *expected_value, bool expected_case_insensitive, int expected_retval) {
|
||||||
_cleanup_free_ char *str = NULL;
|
_cleanup_free_ char *str = NULL;
|
||||||
char *value = UINT_TO_PTR(0x12345678U);
|
char *value = UINT_TO_PTR(0x12345678U);
|
||||||
char *endpos = UINT_TO_PTR(0x87654321U);
|
char *endpos = UINT_TO_PTR(0x87654321U);
|
||||||
|
bool i;
|
||||||
|
|
||||||
log_info("/* %s (%s, %s, %d) */", __func__, in, strnull(expected_value), expected_retval);
|
log_info("/* %s (%s, %s, %d) */", __func__, in, strnull(expected_value), expected_retval);
|
||||||
|
|
||||||
assert_se(str = strdup(in));
|
assert_se(str = strdup(in));
|
||||||
assert_se(udev_rule_parse_value(str, &value, &endpos) == expected_retval);
|
assert_se(udev_rule_parse_value(str, &value, &endpos, &i) == expected_retval);
|
||||||
if (expected_retval < 0) {
|
if (expected_retval < 0) {
|
||||||
/* not modified on failure */
|
/* not modified on failure */
|
||||||
assert_se(value == UINT_TO_PTR(0x12345678U));
|
assert_se(value == UINT_TO_PTR(0x12345678U));
|
||||||
|
@ -25,6 +26,7 @@ static void test_udev_rule_parse_value_one(const char *in, const char *expected_
|
||||||
* so it could be safely interpreted as nulstr.
|
* so it could be safely interpreted as nulstr.
|
||||||
*/
|
*/
|
||||||
assert_se(value[strlen(value) + 1] == '\0');
|
assert_se(value[strlen(value) + 1] == '\0');
|
||||||
|
assert_se(i == expected_case_insensitive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,45 +35,61 @@ TEST(udev_rule_parse_value) {
|
||||||
* parsed: valid operand
|
* parsed: valid operand
|
||||||
* use the following command to help generate textual C strings:
|
* use the following command to help generate textual C strings:
|
||||||
* python3 -c 'import json; print(json.dumps(input()))' */
|
* python3 -c 'import json; print(json.dumps(input()))' */
|
||||||
test_udev_rule_parse_value_one("\"valid operand\"", "valid operand", 0);
|
test_udev_rule_parse_value_one("\"valid operand\"", "valid operand", /* case_insensitive = */ false, 0);
|
||||||
/* input: "va'l\'id\"op\"erand"
|
/* input: "va'l\'id\"op\"erand"
|
||||||
* parsed: va'l\'id"op"erand */
|
* parsed: va'l\'id"op"erand */
|
||||||
test_udev_rule_parse_value_one("\"va'l\\'id\\\"op\\\"erand\"", "va'l\\'id\"op\"erand", 0);
|
test_udev_rule_parse_value_one("\"va'l\\'id\\\"op\\\"erand\"", "va'l\\'id\"op\"erand", /* case_insensitive = */ false, 0);
|
||||||
test_udev_rule_parse_value_one("no quotes", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("no quotes", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
test_udev_rule_parse_value_one("\"\\\\a\\b\\x\\y\"", "\\\\a\\b\\x\\y", 0);
|
test_udev_rule_parse_value_one("\"\\\\a\\b\\x\\y\"", "\\\\a\\b\\x\\y", /* case_insensitive = */ false, 0);
|
||||||
test_udev_rule_parse_value_one("\"reject\0nul\"", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("\"reject\0nul\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: e"" */
|
/* input: e"" */
|
||||||
test_udev_rule_parse_value_one("e\"\"", "", 0);
|
test_udev_rule_parse_value_one("e\"\"", "", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"1234" */
|
/* input: e"1234" */
|
||||||
test_udev_rule_parse_value_one("e\"1234\"", "1234", 0);
|
test_udev_rule_parse_value_one("e\"1234\"", "1234", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"\"" */
|
/* input: e"\"" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\"\"", "\"", 0);
|
test_udev_rule_parse_value_one("e\"\\\"\"", "\"", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"\ */
|
/* input: e"\ */
|
||||||
test_udev_rule_parse_value_one("e\"\\", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: e"\" */
|
/* input: e"\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\"", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: e"\\" */
|
/* input: e"\\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\"", "\\", 0);
|
test_udev_rule_parse_value_one("e\"\\\\\"", "\\", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"\\\" */
|
/* input: e"\\\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\\\"", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\\\\\\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: e"\\\"" */
|
/* input: e"\\\"" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\\\"\"", "\\\"", 0);
|
test_udev_rule_parse_value_one("e\"\\\\\\\"\"", "\\\"", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"\\\\" */
|
/* input: e"\\\\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\\\\\"", "\\\\", 0);
|
test_udev_rule_parse_value_one("e\"\\\\\\\\\"", "\\\\", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"operand with newline\n" */
|
/* input: e"operand with newline\n" */
|
||||||
test_udev_rule_parse_value_one("e\"operand with newline\\n\"", "operand with newline\n", 0);
|
test_udev_rule_parse_value_one("e\"operand with newline\\n\"", "operand with newline\n", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"single\rcharacter\t\aescape\bsequence" */
|
/* input: e"single\rcharacter\t\aescape\bsequence" */
|
||||||
test_udev_rule_parse_value_one(
|
test_udev_rule_parse_value_one(
|
||||||
"e\"single\\rcharacter\\t\\aescape\\bsequence\"", "single\rcharacter\t\aescape\bsequence", 0);
|
"e\"single\\rcharacter\\t\\aescape\\bsequence\"", "single\rcharacter\t\aescape\bsequence", /* case_insensitive = */ false, 0);
|
||||||
/* input: e"reject\invalid escape sequence" */
|
/* input: e"reject\invalid escape sequence" */
|
||||||
test_udev_rule_parse_value_one("e\"reject\\invalid escape sequence", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("e\"reject\\invalid escape sequence", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: e"\ */
|
/* input: e"\ */
|
||||||
test_udev_rule_parse_value_one("e\"\\", NULL, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
/* input: "s\u1d1c\u1d04\u029c \u1d1c\u0274\u026a\u1d04\u1d0f\u1d05\u1d07 \U0001d568\U0001d560\U0001d568" */
|
/* input: "s\u1d1c\u1d04\u029c \u1d1c\u0274\u026a\u1d04\u1d0f\u1d05\u1d07 \U0001d568\U0001d560\U0001d568" */
|
||||||
test_udev_rule_parse_value_one(
|
test_udev_rule_parse_value_one(
|
||||||
"e\"s\\u1d1c\\u1d04\\u029c \\u1d1c\\u0274\\u026a\\u1d04\\u1d0f\\u1d05\\u1d07 \\U0001d568\\U0001d560\\U0001d568\"",
|
"e\"s\\u1d1c\\u1d04\\u029c \\u1d1c\\u0274\\u026a\\u1d04\\u1d0f\\u1d05\\u1d07 \\U0001d568\\U0001d560\\U0001d568\"",
|
||||||
"s\xe1\xb4\x9c\xe1\xb4\x84\xca\x9c \xe1\xb4\x9c\xc9\xb4\xc9\xaa\xe1\xb4\x84\xe1\xb4\x8f\xe1\xb4\x85\xe1\xb4\x87 \xf0\x9d\x95\xa8\xf0\x9d\x95\xa0\xf0\x9d\x95\xa8",
|
"s\xe1\xb4\x9c\xe1\xb4\x84\xca\x9c \xe1\xb4\x9c\xc9\xb4\xc9\xaa\xe1\xb4\x84\xe1\xb4\x8f\xe1\xb4\x85\xe1\xb4\x87 \xf0\x9d\x95\xa8\xf0\x9d\x95\xa0\xf0\x9d\x95\xa8",
|
||||||
0);
|
/* case_insensitive = */ false, 0);
|
||||||
|
/* input: i"ABCD1234" */
|
||||||
|
test_udev_rule_parse_value_one("i\"ABCD1234\"", "ABCD1234", /* case_insensitive = */ true, 0);
|
||||||
|
/* input: i"ABCD1234" */
|
||||||
|
test_udev_rule_parse_value_one("e\"ABCD1234\"", "ABCD1234", /* case_insensitive = */ false, 0);
|
||||||
|
/* input: ei"\\"ABCD1234 */
|
||||||
|
test_udev_rule_parse_value_one("ei\"\\\\ABCD1234\"", "\\ABCD1234", /* case_insensitive = */ true, 0);
|
||||||
|
/* input: ie"\\"ABCD1234 */
|
||||||
|
test_udev_rule_parse_value_one("ie\"\\\\ABCD1234\"", "\\ABCD1234", /* case_insensitive = */ true, 0);
|
||||||
|
/* input: i */
|
||||||
|
test_udev_rule_parse_value_one("i", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
|
/* input: ee"" */
|
||||||
|
test_udev_rule_parse_value_one("ee\"\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
|
/* input: iei"" */
|
||||||
|
test_udev_rule_parse_value_one("iei\"\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
|
/* input: a"" */
|
||||||
|
test_udev_rule_parse_value_one("a\"\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||||
|
|
|
@ -63,9 +63,15 @@ typedef enum {
|
||||||
MATCH_TYPE_GLOB_WITH_EMPTY, /* shell globs ?,*,[] with empty string, e.g., "|foo*" */
|
MATCH_TYPE_GLOB_WITH_EMPTY, /* shell globs ?,*,[] with empty string, e.g., "|foo*" */
|
||||||
MATCH_TYPE_SUBSYSTEM, /* "subsystem", "bus", or "class" */
|
MATCH_TYPE_SUBSYSTEM, /* "subsystem", "bus", or "class" */
|
||||||
_MATCH_TYPE_MAX,
|
_MATCH_TYPE_MAX,
|
||||||
|
|
||||||
|
_MATCH_TYPE_MASK = (1 << 5) - 1,
|
||||||
|
MATCH_REMOVE_TRAILING_WHITESPACE = 1 << 5, /* Remove trailing whitespaces in attribute */
|
||||||
|
MATCH_CASE_INSENSITIVE = 1 << 6, /* string or pattern is matched case-insensitively */
|
||||||
_MATCH_TYPE_INVALID = -EINVAL,
|
_MATCH_TYPE_INVALID = -EINVAL,
|
||||||
} UdevRuleMatchType;
|
} UdevRuleMatchType;
|
||||||
|
|
||||||
|
assert_cc(_MATCH_TYPE_MAX <= _MATCH_TYPE_MASK);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SUBST_TYPE_PLAIN, /* no substitution */
|
SUBST_TYPE_PLAIN, /* no substitution */
|
||||||
SUBST_TYPE_FORMAT, /* % or $ */
|
SUBST_TYPE_FORMAT, /* % or $ */
|
||||||
|
@ -155,8 +161,7 @@ struct UdevRuleToken {
|
||||||
UdevRuleTokenType type:8;
|
UdevRuleTokenType type:8;
|
||||||
UdevRuleOperatorType op:8;
|
UdevRuleOperatorType op:8;
|
||||||
UdevRuleMatchType match_type:8;
|
UdevRuleMatchType match_type:8;
|
||||||
UdevRuleSubstituteType attr_subst_type:7;
|
UdevRuleSubstituteType attr_subst_type:8;
|
||||||
bool attr_match_remove_trailing_whitespace:1;
|
|
||||||
const char *value;
|
const char *value;
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
|
@ -295,6 +300,7 @@ struct UdevRules {
|
||||||
|
|
||||||
#define log_line_invalid_op(line, key) _log_line_invalid_token(line, key, "operator")
|
#define log_line_invalid_op(line, key) _log_line_invalid_token(line, key, "operator")
|
||||||
#define log_line_invalid_attr(line, key) _log_line_invalid_token(line, key, "attribute")
|
#define log_line_invalid_attr(line, key) _log_line_invalid_token(line, key, "attribute")
|
||||||
|
#define log_line_invalid_prefix(line, key) _log_line_invalid_token(line, key, "prefix 'i'")
|
||||||
|
|
||||||
#define log_line_invalid_attr_format(line, key, attr, offset, hint) \
|
#define log_line_invalid_attr_format(line, key, attr, offset, hint) \
|
||||||
log_line_error_errno(line, SYNTHETIC_ERRNO(EINVAL), \
|
log_line_error_errno(line, SYNTHETIC_ERRNO(EINVAL), \
|
||||||
|
@ -488,12 +494,10 @@ static bool type_has_nulstr_value(UdevRuleTokenType type) {
|
||||||
return type < TK_M_TEST || type == TK_M_RESULT;
|
return type < TK_M_TEST || type == TK_M_RESULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type, UdevRuleOperatorType op, char *value, void *data) {
|
static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type, UdevRuleOperatorType op, char *value, void *data, bool is_case_insensitive) {
|
||||||
_cleanup_(udev_rule_token_freep) UdevRuleToken *token = NULL;
|
_cleanup_(udev_rule_token_freep) UdevRuleToken *token = NULL;
|
||||||
UdevRuleMatchType match_type = _MATCH_TYPE_INVALID;
|
UdevRuleMatchType match_type = _MATCH_TYPE_INVALID;
|
||||||
UdevRuleSubstituteType subst_type = _SUBST_TYPE_INVALID;
|
UdevRuleSubstituteType subst_type = _SUBST_TYPE_INVALID;
|
||||||
bool remove_trailing_whitespace = false;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
assert(rule_line);
|
assert(rule_line);
|
||||||
assert(type >= 0 && type < _TK_TYPE_MAX);
|
assert(type >= 0 && type < _TK_TYPE_MAX);
|
||||||
|
@ -552,16 +556,21 @@ static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IN_SET(type, TK_M_ATTR, TK_M_PARENTS_ATTR)) {
|
if (IN_SET(type, TK_M_ATTR, TK_M_PARENTS_ATTR)) {
|
||||||
|
size_t len;
|
||||||
|
|
||||||
assert(value);
|
assert(value);
|
||||||
assert(data);
|
assert(data);
|
||||||
|
assert(match_type >= 0 && match_type < _MATCH_TYPE_MAX);
|
||||||
|
|
||||||
len = strlen(value);
|
len = strlen(value);
|
||||||
if (len > 0 && !isspace(value[len - 1]))
|
if (len > 0 && !isspace(value[len - 1]))
|
||||||
remove_trailing_whitespace = true;
|
match_type |= MATCH_REMOVE_TRAILING_WHITESPACE;
|
||||||
|
|
||||||
subst_type = rule_get_substitution_type(data);
|
subst_type = rule_get_substitution_type(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SET_FLAG(match_type, MATCH_CASE_INSENSITIVE, is_case_insensitive);
|
||||||
|
|
||||||
token = new(UdevRuleToken, 1);
|
token = new(UdevRuleToken, 1);
|
||||||
if (!token)
|
if (!token)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -573,7 +582,6 @@ static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type,
|
||||||
.data = data,
|
.data = data,
|
||||||
.match_type = match_type,
|
.match_type = match_type,
|
||||||
.attr_subst_type = subst_type,
|
.attr_subst_type = subst_type,
|
||||||
.attr_match_remove_trailing_whitespace = remove_trailing_whitespace,
|
|
||||||
.rule_line = rule_line,
|
.rule_line = rule_line,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -621,7 +629,7 @@ static int check_attr_format_and_warn(UdevRuleLine *line, const char *key, const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, UdevRuleOperatorType op, char *value) {
|
static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, UdevRuleOperatorType op, char *value, bool is_case_insensitive) {
|
||||||
ResolveNameTiming resolve_name_timing = LINE_GET_RULES(rule_line)->resolve_name_timing;
|
ResolveNameTiming resolve_name_timing = LINE_GET_RULES(rule_line)->resolve_name_timing;
|
||||||
bool is_match = IN_SET(op, OP_MATCH, OP_NOMATCH);
|
bool is_match = IN_SET(op, OP_MATCH, OP_NOMATCH);
|
||||||
int r;
|
int r;
|
||||||
|
@ -629,35 +637,39 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
assert(key);
|
assert(key);
|
||||||
assert(value);
|
assert(value);
|
||||||
|
|
||||||
|
if (!is_match && is_case_insensitive)
|
||||||
|
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
||||||
|
"Invalid prefix 'i' for '%s'. The 'i' prefix can be specified only for '==' or '!=' operator.", key);
|
||||||
|
|
||||||
if (streq(key, "ACTION")) {
|
if (streq(key, "ACTION")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_ACTION, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_ACTION, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "DEVPATH")) {
|
} else if (streq(key, "DEVPATH")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_DEVPATH, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_DEVPATH, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "KERNEL")) {
|
} else if (streq(key, "KERNEL")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_KERNEL, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_KERNEL, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "SYMLINK")) {
|
} else if (streq(key, "SYMLINK")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match) {
|
if (!is_match) {
|
||||||
check_value_format_and_warn(rule_line, key, value, false);
|
check_value_format_and_warn(rule_line, key, value, false);
|
||||||
r = rule_line_add_token(rule_line, TK_A_DEVLINK, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_DEVLINK, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_DEVLINK, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_DEVLINK, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "NAME")) {
|
} else if (streq(key, "NAME")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -677,9 +689,9 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
"Ignoring NAME=\"\", as udev will not delete any network interfaces.");
|
"Ignoring NAME=\"\", as udev will not delete any network interfaces.");
|
||||||
check_value_format_and_warn(rule_line, key, value, false);
|
check_value_format_and_warn(rule_line, key, value, false);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_NAME, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_NAME, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_NAME, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_NAME, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "ENV")) {
|
} else if (streq(key, "ENV")) {
|
||||||
if (isempty(attr))
|
if (isempty(attr))
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -697,15 +709,15 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
|
|
||||||
check_value_format_and_warn(rule_line, key, value, false);
|
check_value_format_and_warn(rule_line, key, value, false);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_ENV, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_A_ENV, op, value, attr, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_ENV, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_M_ENV, op, value, attr, is_case_insensitive);
|
||||||
} else if (streq(key, "CONST")) {
|
} else if (streq(key, "CONST")) {
|
||||||
if (isempty(attr) || !STR_IN_SET(attr, "arch", "virt"))
|
if (isempty(attr) || !STR_IN_SET(attr, "arch", "virt"))
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
r = rule_line_add_token(rule_line, TK_M_CONST, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_M_CONST, op, value, attr, is_case_insensitive);
|
||||||
} else if (streq(key, "TAG")) {
|
} else if (streq(key, "TAG")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -717,9 +729,9 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (!is_match) {
|
if (!is_match) {
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_TAG, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_TAG, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_TAG, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_TAG, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "SUBSYSTEM")) {
|
} else if (streq(key, "SUBSYSTEM")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -729,14 +741,14 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (STR_IN_SET(value, "bus", "class"))
|
if (STR_IN_SET(value, "bus", "class"))
|
||||||
log_line_warning(rule_line, "\"%s\" must be specified as \"subsystem\".", value);
|
log_line_warning(rule_line, "\"%s\" must be specified as \"subsystem\".", value);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_SUBSYSTEM, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_SUBSYSTEM, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "DRIVER")) {
|
} else if (streq(key, "DRIVER")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_DRIVER, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_DRIVER, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "ATTR")) {
|
} else if (streq(key, "ATTR")) {
|
||||||
r = check_attr_format_and_warn(rule_line, key, attr);
|
r = check_attr_format_and_warn(rule_line, key, attr);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -750,9 +762,9 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
|
|
||||||
if (!is_match) {
|
if (!is_match) {
|
||||||
check_value_format_and_warn(rule_line, key, value, false);
|
check_value_format_and_warn(rule_line, key, value, false);
|
||||||
r = rule_line_add_token(rule_line, TK_A_ATTR, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_A_ATTR, op, value, attr, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_ATTR, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_M_ATTR, op, value, attr, is_case_insensitive);
|
||||||
} else if (streq(key, "SYSCTL")) {
|
} else if (streq(key, "SYSCTL")) {
|
||||||
r = check_attr_format_and_warn(rule_line, key, attr);
|
r = check_attr_format_and_warn(rule_line, key, attr);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -766,30 +778,30 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
|
|
||||||
if (!is_match) {
|
if (!is_match) {
|
||||||
check_value_format_and_warn(rule_line, key, value, false);
|
check_value_format_and_warn(rule_line, key, value, false);
|
||||||
r = rule_line_add_token(rule_line, TK_A_SYSCTL, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_A_SYSCTL, op, value, attr, /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_SYSCTL, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_M_SYSCTL, op, value, attr, is_case_insensitive);
|
||||||
} else if (streq(key, "KERNELS")) {
|
} else if (streq(key, "KERNELS")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_KERNEL, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_KERNEL, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "SUBSYSTEMS")) {
|
} else if (streq(key, "SUBSYSTEMS")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_SUBSYSTEM, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_SUBSYSTEM, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "DRIVERS")) {
|
} else if (streq(key, "DRIVERS")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_DRIVER, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_DRIVER, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "ATTRS")) {
|
} else if (streq(key, "ATTRS")) {
|
||||||
r = check_attr_format_and_warn(rule_line, key, attr);
|
r = check_attr_format_and_warn(rule_line, key, attr);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -802,14 +814,14 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (strstr(attr, "../"))
|
if (strstr(attr, "../"))
|
||||||
log_line_warning(rule_line, "Direct reference to parent sysfs directory, may break in future kernels.");
|
log_line_warning(rule_line, "Direct reference to parent sysfs directory, may break in future kernels.");
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_ATTR, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_ATTR, op, value, attr, is_case_insensitive);
|
||||||
} else if (streq(key, "TAGS")) {
|
} else if (streq(key, "TAGS")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_TAG, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_TAG, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "TEST")) {
|
} else if (streq(key, "TEST")) {
|
||||||
mode_t mode = MODE_INVALID;
|
mode_t mode = MODE_INVALID;
|
||||||
|
|
||||||
|
@ -821,8 +833,10 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
if (is_case_insensitive)
|
||||||
|
return log_line_invalid_prefix(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_TEST, op, value, MODE_TO_PTR(mode));
|
r = rule_line_add_token(rule_line, TK_M_TEST, op, value, MODE_TO_PTR(mode), is_case_insensitive);
|
||||||
} else if (streq(key, "PROGRAM")) {
|
} else if (streq(key, "PROGRAM")) {
|
||||||
if (attr)
|
if (attr)
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -831,8 +845,10 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
op = OP_MATCH;
|
op = OP_MATCH;
|
||||||
|
if (is_case_insensitive)
|
||||||
|
return log_line_invalid_prefix(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_PROGRAM, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_PROGRAM, op, value, NULL, /* is_case_insensitive */ false);
|
||||||
} else if (streq(key, "IMPORT")) {
|
} else if (streq(key, "IMPORT")) {
|
||||||
if (isempty(attr))
|
if (isempty(attr))
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
|
@ -841,18 +857,20 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
op = OP_MATCH;
|
op = OP_MATCH;
|
||||||
|
if (is_case_insensitive)
|
||||||
|
return log_line_invalid_prefix(rule_line, key);
|
||||||
|
|
||||||
if (streq(attr, "file"))
|
if (streq(attr, "file"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_FILE, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_FILE, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(attr, "program")) {
|
else if (streq(attr, "program")) {
|
||||||
UdevBuiltinCommand cmd;
|
UdevBuiltinCommand cmd;
|
||||||
|
|
||||||
cmd = udev_builtin_lookup(value);
|
cmd = udev_builtin_lookup(value);
|
||||||
if (cmd >= 0) {
|
if (cmd >= 0) {
|
||||||
log_line_debug(rule_line, "Found builtin command '%s' for %s, replacing attribute.", value, key);
|
log_line_debug(rule_line, "Found builtin command '%s' for %s, replacing attribute.", value, key);
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd), /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_PROGRAM, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_PROGRAM, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else if (streq(attr, "builtin")) {
|
} else if (streq(attr, "builtin")) {
|
||||||
UdevBuiltinCommand cmd;
|
UdevBuiltinCommand cmd;
|
||||||
|
|
||||||
|
@ -860,13 +878,13 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (cmd < 0)
|
if (cmd < 0)
|
||||||
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Unknown builtin command: %s", value);
|
"Unknown builtin command: %s", value);
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd), /* is_case_insensitive = */ false);
|
||||||
} else if (streq(attr, "db"))
|
} else if (streq(attr, "db"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_DB, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_DB, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(attr, "cmdline"))
|
else if (streq(attr, "cmdline"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_CMDLINE, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_CMDLINE, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(attr, "parent"))
|
else if (streq(attr, "parent"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_PARENT, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_PARENT, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
else
|
else
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
} else if (streq(key, "RESULT")) {
|
} else if (streq(key, "RESULT")) {
|
||||||
|
@ -875,7 +893,7 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (!is_match)
|
if (!is_match)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_M_RESULT, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_M_RESULT, op, value, NULL, is_case_insensitive);
|
||||||
} else if (streq(key, "OPTIONS")) {
|
} else if (streq(key, "OPTIONS")) {
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
|
@ -887,24 +905,24 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
op = OP_ASSIGN;
|
op = OP_ASSIGN;
|
||||||
|
|
||||||
if (streq(value, "string_escape=none"))
|
if (streq(value, "string_escape=none"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_NONE, op, NULL, NULL);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_NONE, op, NULL, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(value, "string_escape=replace"))
|
else if (streq(value, "string_escape=replace"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_REPLACE, op, NULL, NULL);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_REPLACE, op, NULL, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(value, "db_persist"))
|
else if (streq(value, "db_persist"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DB_PERSIST, op, NULL, NULL);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DB_PERSIST, op, NULL, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(value, "watch"))
|
else if (streq(value, "watch"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(1));
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(1), /* is_case_insensitive = */ false);
|
||||||
else if (streq(value, "nowatch"))
|
else if (streq(value, "nowatch"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(0));
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(0), /* is_case_insensitive = */ false);
|
||||||
else if ((tmp = startswith(value, "static_node=")))
|
else if ((tmp = startswith(value, "static_node=")))
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STATIC_NODE, op, tmp, NULL);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STATIC_NODE, op, tmp, NULL, /* is_case_insensitive = */ false);
|
||||||
else if ((tmp = startswith(value, "link_priority="))) {
|
else if ((tmp = startswith(value, "link_priority="))) {
|
||||||
int prio;
|
int prio;
|
||||||
|
|
||||||
r = safe_atoi(tmp, &prio);
|
r = safe_atoi(tmp, &prio);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_line_error_errno(rule_line, r, "Failed to parse link priority '%s': %m", tmp);
|
return log_line_error_errno(rule_line, r, "Failed to parse link priority '%s': %m", tmp);
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DEVLINK_PRIORITY, op, NULL, INT_TO_PTR(prio));
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DEVLINK_PRIORITY, op, NULL, INT_TO_PTR(prio), /* is_case_insensitive = */ false);
|
||||||
} else if ((tmp = startswith(value, "log_level="))) {
|
} else if ((tmp = startswith(value, "log_level="))) {
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
|
@ -915,7 +933,7 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (level < 0)
|
if (level < 0)
|
||||||
return log_line_error_errno(rule_line, level, "Failed to parse log level '%s': %m", tmp);
|
return log_line_error_errno(rule_line, level, "Failed to parse log level '%s': %m", tmp);
|
||||||
}
|
}
|
||||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_LOG_LEVEL, op, NULL, INT_TO_PTR(level));
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_LOG_LEVEL, op, NULL, INT_TO_PTR(level), /* is_case_insensitive = */ false);
|
||||||
} else {
|
} else {
|
||||||
log_line_warning(rule_line, "Invalid value for OPTIONS key, ignoring: '%s'", value);
|
log_line_warning(rule_line, "Invalid value for OPTIONS key, ignoring: '%s'", value);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -933,17 +951,17 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_uid(value, &uid) >= 0)
|
if (parse_uid(value, &uid) >= 0)
|
||||||
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid));
|
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid), /* is_case_insensitive = */ false);
|
||||||
else if (resolve_name_timing == RESOLVE_NAME_EARLY &&
|
else if (resolve_name_timing == RESOLVE_NAME_EARLY &&
|
||||||
rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) {
|
rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) {
|
||||||
r = rule_resolve_user(rule_line, value, &uid);
|
r = rule_resolve_user(rule_line, value, &uid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_line_error_errno(rule_line, r, "Failed to resolve user name '%s': %m", value);
|
return log_line_error_errno(rule_line, r, "Failed to resolve user name '%s': %m", value);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid));
|
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid), /* is_case_insensitive = */ false);
|
||||||
} else if (resolve_name_timing != RESOLVE_NAME_NEVER) {
|
} else if (resolve_name_timing != RESOLVE_NAME_NEVER) {
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
r = rule_line_add_token(rule_line, TK_A_OWNER, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_OWNER, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else {
|
} else {
|
||||||
log_line_debug(rule_line, "User name resolution is disabled, ignoring %s=\"%s\".", key, value);
|
log_line_debug(rule_line, "User name resolution is disabled, ignoring %s=\"%s\".", key, value);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -961,17 +979,17 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_gid(value, &gid) >= 0)
|
if (parse_gid(value, &gid) >= 0)
|
||||||
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid));
|
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid), /* is_case_insensitive = */ false);
|
||||||
else if (resolve_name_timing == RESOLVE_NAME_EARLY &&
|
else if (resolve_name_timing == RESOLVE_NAME_EARLY &&
|
||||||
rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) {
|
rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) {
|
||||||
r = rule_resolve_group(rule_line, value, &gid);
|
r = rule_resolve_group(rule_line, value, &gid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_line_error_errno(rule_line, r, "Failed to resolve group name '%s': %m", value);
|
return log_line_error_errno(rule_line, r, "Failed to resolve group name '%s': %m", value);
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid));
|
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid), /* is_case_insensitive = */ false);
|
||||||
} else if (resolve_name_timing != RESOLVE_NAME_NEVER) {
|
} else if (resolve_name_timing != RESOLVE_NAME_NEVER) {
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
r = rule_line_add_token(rule_line, TK_A_GROUP, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_GROUP, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
} else {
|
} else {
|
||||||
log_line_debug(rule_line, "Resolving group name is disabled, ignoring GROUP=\"%s\".", value);
|
log_line_debug(rule_line, "Resolving group name is disabled, ignoring GROUP=\"%s\".", value);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -989,10 +1007,10 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_mode(value, &mode) >= 0)
|
if (parse_mode(value, &mode) >= 0)
|
||||||
r = rule_line_add_token(rule_line, TK_A_MODE_ID, op, NULL, MODE_TO_PTR(mode));
|
r = rule_line_add_token(rule_line, TK_A_MODE_ID, op, NULL, MODE_TO_PTR(mode), /* is_case_insensitive = */ false);
|
||||||
else {
|
else {
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
r = rule_line_add_token(rule_line, TK_A_MODE, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_MODE, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
}
|
}
|
||||||
} else if (streq(key, "SECLABEL")) {
|
} else if (streq(key, "SECLABEL")) {
|
||||||
if (isempty(attr))
|
if (isempty(attr))
|
||||||
|
@ -1005,13 +1023,13 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
op = OP_ASSIGN;
|
op = OP_ASSIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = rule_line_add_token(rule_line, TK_A_SECLABEL, op, value, attr);
|
r = rule_line_add_token(rule_line, TK_A_SECLABEL, op, value, attr, /* is_case_insensitive = */ false);
|
||||||
} else if (streq(key, "RUN")) {
|
} else if (streq(key, "RUN")) {
|
||||||
if (is_match || op == OP_REMOVE)
|
if (is_match || op == OP_REMOVE)
|
||||||
return log_line_invalid_op(rule_line, key);
|
return log_line_invalid_op(rule_line, key);
|
||||||
check_value_format_and_warn(rule_line, key, value, true);
|
check_value_format_and_warn(rule_line, key, value, true);
|
||||||
if (!attr || streq(attr, "program"))
|
if (!attr || streq(attr, "program"))
|
||||||
r = rule_line_add_token(rule_line, TK_A_RUN_PROGRAM, op, value, NULL);
|
r = rule_line_add_token(rule_line, TK_A_RUN_PROGRAM, op, value, NULL, /* is_case_insensitive = */ false);
|
||||||
else if (streq(attr, "builtin")) {
|
else if (streq(attr, "builtin")) {
|
||||||
UdevBuiltinCommand cmd;
|
UdevBuiltinCommand cmd;
|
||||||
|
|
||||||
|
@ -1019,7 +1037,7 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
||||||
if (cmd < 0)
|
if (cmd < 0)
|
||||||
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Unknown builtin command '%s', ignoring.", value);
|
"Unknown builtin command '%s', ignoring.", value);
|
||||||
r = rule_line_add_token(rule_line, TK_A_RUN_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
r = rule_line_add_token(rule_line, TK_A_RUN_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd), /* is_case_insensitive = */ false);
|
||||||
} else
|
} else
|
||||||
return log_line_invalid_attr(rule_line, key);
|
return log_line_invalid_attr(rule_line, key);
|
||||||
} else if (streq(key, "GOTO")) {
|
} else if (streq(key, "GOTO")) {
|
||||||
|
@ -1119,13 +1137,30 @@ static void check_token_delimiters(UdevRuleLine *rule_line, const char *line) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
|
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos, bool *ret_is_case_insensitive) {
|
||||||
char *i, *j;
|
char *i, *j;
|
||||||
bool is_escaped;
|
bool is_escaped = false, is_case_insensitive = false;
|
||||||
|
|
||||||
|
assert(str);
|
||||||
|
assert(ret_value);
|
||||||
|
assert(ret_endpos);
|
||||||
|
assert(ret_is_case_insensitive);
|
||||||
|
|
||||||
|
/* check if string is prefixed with:
|
||||||
|
* - "e" for escaped
|
||||||
|
* - "i" for case insensitive match
|
||||||
|
*
|
||||||
|
* Note both e and i can be set but do not allow duplicates ("eei", "eii"). */
|
||||||
|
for (const char *k = str; *k != '"' && k < str + 2; k++)
|
||||||
|
if (*k == 'e' && !is_escaped)
|
||||||
|
is_escaped = true;
|
||||||
|
else if (*k == 'i' && !is_case_insensitive)
|
||||||
|
is_case_insensitive = true;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/* value must be double quotated */
|
/* value must be double quotated */
|
||||||
is_escaped = str[0] == 'e';
|
str += is_escaped + is_case_insensitive;
|
||||||
str += is_escaped;
|
|
||||||
if (str[0] != '"')
|
if (str[0] != '"')
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -1172,10 +1207,11 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
|
||||||
|
|
||||||
*ret_value = str;
|
*ret_value = str;
|
||||||
*ret_endpos = i + 1;
|
*ret_endpos = i + 1;
|
||||||
|
*ret_is_case_insensitive = is_case_insensitive;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOperatorType *ret_op, char **ret_value) {
|
static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOperatorType *ret_op, char **ret_value, bool *ret_is_case_insensitive) {
|
||||||
char *key_begin, *key_end, *attr, *tmp;
|
char *key_begin, *key_end, *attr, *tmp;
|
||||||
UdevRuleOperatorType op;
|
UdevRuleOperatorType op;
|
||||||
int r;
|
int r;
|
||||||
|
@ -1185,6 +1221,7 @@ static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOper
|
||||||
assert(ret_key);
|
assert(ret_key);
|
||||||
assert(ret_op);
|
assert(ret_op);
|
||||||
assert(ret_value);
|
assert(ret_value);
|
||||||
|
assert(ret_is_case_insensitive);
|
||||||
|
|
||||||
key_begin = skip_leading_chars(*line, WHITESPACE ",");
|
key_begin = skip_leading_chars(*line, WHITESPACE ",");
|
||||||
|
|
||||||
|
@ -1219,7 +1256,7 @@ static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOper
|
||||||
|
|
||||||
tmp += op == OP_ASSIGN ? 1 : 2;
|
tmp += op == OP_ASSIGN ? 1 : 2;
|
||||||
tmp = skip_leading_chars(tmp, NULL);
|
tmp = skip_leading_chars(tmp, NULL);
|
||||||
r = udev_rule_parse_value(tmp, ret_value, line);
|
r = udev_rule_parse_value(tmp, ret_value, line, ret_is_case_insensitive);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1291,17 +1328,18 @@ static int rule_add_line(UdevRuleFile *rule_file, const char *line_str, unsigned
|
||||||
for (p = rule_line->line; !isempty(p); ) {
|
for (p = rule_line->line; !isempty(p); ) {
|
||||||
char *key, *attr, *value;
|
char *key, *attr, *value;
|
||||||
UdevRuleOperatorType op;
|
UdevRuleOperatorType op;
|
||||||
|
bool is_case_insensitive;
|
||||||
|
|
||||||
if (extra_checks)
|
if (extra_checks)
|
||||||
check_token_delimiters(rule_line, p);
|
check_token_delimiters(rule_line, p);
|
||||||
|
|
||||||
r = parse_line(&p, &key, &attr, &op, &value);
|
r = parse_line(&p, &key, &attr, &op, &value, &is_case_insensitive);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_line_error_errno(rule_line, r, "Invalid key/value pair, ignoring.");
|
return log_line_error_errno(rule_line, r, "Invalid key/value pair, ignoring.");
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
r = parse_token(rule_line, key, attr, op, value);
|
r = parse_token(rule_line, key, attr, op, value, is_case_insensitive);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1412,7 +1450,6 @@ static bool tokens_eq(const UdevRuleToken *a, const UdevRuleToken *b) {
|
||||||
assert(b);
|
assert(b);
|
||||||
|
|
||||||
return a->attr_subst_type == b->attr_subst_type &&
|
return a->attr_subst_type == b->attr_subst_type &&
|
||||||
a->attr_match_remove_trailing_whitespace == b->attr_match_remove_trailing_whitespace &&
|
|
||||||
token_type_and_value_eq(a, b) &&
|
token_type_and_value_eq(a, b) &&
|
||||||
token_type_and_data_eq(a, b);
|
token_type_and_data_eq(a, b);
|
||||||
}
|
}
|
||||||
|
@ -1427,7 +1464,6 @@ static bool nulstr_tokens_conflict(const UdevRuleToken *a, const UdevRuleToken *
|
||||||
a->op == OP_MATCH &&
|
a->op == OP_MATCH &&
|
||||||
a->match_type == b->match_type &&
|
a->match_type == b->match_type &&
|
||||||
a->attr_subst_type == b->attr_subst_type &&
|
a->attr_subst_type == b->attr_subst_type &&
|
||||||
a->attr_match_remove_trailing_whitespace == b->attr_match_remove_trailing_whitespace &&
|
|
||||||
token_type_and_data_eq(a, b)))
|
token_type_and_data_eq(a, b)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1696,7 +1732,7 @@ bool udev_rules_should_reload(UdevRules *rules) {
|
||||||
|
|
||||||
static bool token_match_string(UdevRuleToken *token, const char *str) {
|
static bool token_match_string(UdevRuleToken *token, const char *str) {
|
||||||
const char *value;
|
const char *value;
|
||||||
bool match = false;
|
bool match = false, case_insensitive;
|
||||||
|
|
||||||
assert(token);
|
assert(token);
|
||||||
assert(token->value);
|
assert(token->value);
|
||||||
|
@ -1704,12 +1740,16 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
|
||||||
|
|
||||||
str = strempty(str);
|
str = strempty(str);
|
||||||
value = token->value;
|
value = token->value;
|
||||||
|
case_insensitive = FLAGS_SET(token->match_type, MATCH_CASE_INSENSITIVE);
|
||||||
|
|
||||||
switch (token->match_type) {
|
switch (token->match_type & _MATCH_TYPE_MASK) {
|
||||||
case MATCH_TYPE_EMPTY:
|
case MATCH_TYPE_EMPTY:
|
||||||
match = isempty(str);
|
match = isempty(str);
|
||||||
break;
|
break;
|
||||||
case MATCH_TYPE_SUBSYSTEM:
|
case MATCH_TYPE_SUBSYSTEM:
|
||||||
|
if (case_insensitive)
|
||||||
|
match = STRCASE_IN_SET(str, "subsystem", "class", "bus");
|
||||||
|
else
|
||||||
match = STR_IN_SET(str, "subsystem", "class", "bus");
|
match = STR_IN_SET(str, "subsystem", "class", "bus");
|
||||||
break;
|
break;
|
||||||
case MATCH_TYPE_PLAIN_WITH_EMPTY:
|
case MATCH_TYPE_PLAIN_WITH_EMPTY:
|
||||||
|
@ -1720,7 +1760,7 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
|
||||||
_fallthrough_;
|
_fallthrough_;
|
||||||
case MATCH_TYPE_PLAIN:
|
case MATCH_TYPE_PLAIN:
|
||||||
NULSTR_FOREACH(i, value)
|
NULSTR_FOREACH(i, value)
|
||||||
if (streq(i, str)) {
|
if (case_insensitive ? strcaseeq(i, str) : streq(i, str)) {
|
||||||
match = true;
|
match = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1733,7 +1773,7 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
|
||||||
_fallthrough_;
|
_fallthrough_;
|
||||||
case MATCH_TYPE_GLOB:
|
case MATCH_TYPE_GLOB:
|
||||||
NULSTR_FOREACH(i, value)
|
NULSTR_FOREACH(i, value)
|
||||||
if ((fnmatch(i, str, 0) == 0)) {
|
if ((fnmatch(i, str, case_insensitive ? FNM_CASEFOLD : 0) == 0)) {
|
||||||
match = true;
|
match = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1773,7 +1813,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* remove trailing whitespace, if not asked to match for it */
|
/* remove trailing whitespace, if not asked to match for it */
|
||||||
if (token->attr_match_remove_trailing_whitespace) {
|
if (FLAGS_SET(token->match_type, MATCH_REMOVE_TRAILING_WHITESPACE)) {
|
||||||
strscpy(vbuf, sizeof(vbuf), value);
|
strscpy(vbuf, sizeof(vbuf), value);
|
||||||
value = delete_trailing_chars(vbuf, NULL);
|
value = delete_trailing_chars(vbuf, NULL);
|
||||||
}
|
}
|
||||||
|
@ -1785,7 +1825,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* remove trailing whitespace, if not asked to match for it */
|
/* remove trailing whitespace, if not asked to match for it */
|
||||||
if (token->attr_match_remove_trailing_whitespace)
|
if (FLAGS_SET(token->match_type, MATCH_REMOVE_TRAILING_WHITESPACE))
|
||||||
delete_trailing_chars(vbuf, NULL);
|
delete_trailing_chars(vbuf, NULL);
|
||||||
|
|
||||||
return token_match_string(token, vbuf);
|
return token_match_string(token, vbuf);
|
||||||
|
|
|
@ -29,7 +29,7 @@ typedef enum ResolveNameTiming {
|
||||||
_RESOLVE_NAME_TIMING_INVALID = -EINVAL,
|
_RESOLVE_NAME_TIMING_INVALID = -EINVAL,
|
||||||
} ResolveNameTiming;
|
} ResolveNameTiming;
|
||||||
|
|
||||||
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos);
|
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos, bool *ret_is_case_insensitive);
|
||||||
int udev_rules_parse_file(UdevRules *rules, const char *filename, bool extra_checks, UdevRuleFile **ret);
|
int udev_rules_parse_file(UdevRules *rules, const char *filename, bool extra_checks, UdevRuleFile **ret);
|
||||||
unsigned udev_rule_file_get_issues(UdevRuleFile *rule_file);
|
unsigned udev_rule_file_get_issues(UdevRuleFile *rule_file);
|
||||||
UdevRules* udev_rules_new(ResolveNameTiming resolve_name_timing);
|
UdevRules* udev_rules_new(ResolveNameTiming resolve_name_timing);
|
||||||
|
|
|
@ -2313,6 +2313,17 @@ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \"printf %%s 'foo1 foo2' | grep 'foo1 f
|
||||||
SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sd*", SYMLINK+="blockdev"
|
SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sd*", SYMLINK+="blockdev"
|
||||||
KERNEL=="sda6", OPTIONS+="link_priority=10"
|
KERNEL=="sda6", OPTIONS+="link_priority=10"
|
||||||
"""),
|
"""),
|
||||||
|
|
||||||
|
Rules.new(
|
||||||
|
"case insensitive match",
|
||||||
|
Device(
|
||||||
|
"/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
|
||||||
|
exp_links = ["ok"],
|
||||||
|
),
|
||||||
|
|
||||||
|
rules = r"""
|
||||||
|
KERNEL==i"SDA1", SUBSYSTEMS==i"SCSI", ATTRS{vendor}==i"a?a", SYMLINK+="ok"
|
||||||
|
"""),
|
||||||
]
|
]
|
||||||
|
|
||||||
def fork_and_run_udev(action: str, rules: Rules) -> None:
|
def fork_and_run_udev(action: str, rules: Rules) -> None:
|
||||||
|
|
|
@ -237,6 +237,8 @@ test_syntax_error 'ENV=="b"' 'Invalid attribute for ENV.'
|
||||||
test_syntax_error 'ENV{a}-="b"' 'Invalid operator for ENV.'
|
test_syntax_error 'ENV{a}-="b"' 'Invalid operator for ENV.'
|
||||||
test_syntax_error 'ENV{a}:="b"' "ENV key takes '==', '!=', '=', or '+=' operator, assuming '='."
|
test_syntax_error 'ENV{a}:="b"' "ENV key takes '==', '!=', '=', or '+=' operator, assuming '='."
|
||||||
test_syntax_error 'ENV{ACTION}="b"' "Invalid ENV attribute. 'ACTION' cannot be set."
|
test_syntax_error 'ENV{ACTION}="b"' "Invalid ENV attribute. 'ACTION' cannot be set."
|
||||||
|
test_syntax_error 'ENV{a}=i"b"' "Invalid prefix 'i' for 'ENV'. The 'i' prefix can be specified only for '==' or '!=' operator."
|
||||||
|
test_syntax_error 'ENV{a}+=i"b"' "Invalid prefix 'i' for 'ENV'. The 'i' prefix can be specified only for '==' or '!=' operator."
|
||||||
test_syntax_error 'CONST=="b"' 'Invalid attribute for CONST.'
|
test_syntax_error 'CONST=="b"' 'Invalid attribute for CONST.'
|
||||||
test_syntax_error 'CONST{a}=="b"' 'Invalid attribute for CONST.'
|
test_syntax_error 'CONST{a}=="b"' 'Invalid attribute for CONST.'
|
||||||
test_syntax_error 'CONST{arch}="b"' 'Invalid operator for CONST.'
|
test_syntax_error 'CONST{arch}="b"' 'Invalid operator for CONST.'
|
||||||
|
@ -275,10 +277,12 @@ test_syntax_error 'TEST{0644}="b"' 'Invalid operator for TEST.'
|
||||||
test_syntax_error 'PROGRAM{a}=="b"' 'Invalid attribute for PROGRAM.'
|
test_syntax_error 'PROGRAM{a}=="b"' 'Invalid attribute for PROGRAM.'
|
||||||
test_syntax_error 'PROGRAM-="b"' 'Invalid operator for PROGRAM.'
|
test_syntax_error 'PROGRAM-="b"' 'Invalid operator for PROGRAM.'
|
||||||
test_syntax_error 'PROGRAM=="%", NAME="b"' 'Invalid value "%" for PROGRAM (char 1: invalid substitution type), ignoring.'
|
test_syntax_error 'PROGRAM=="%", NAME="b"' 'Invalid value "%" for PROGRAM (char 1: invalid substitution type), ignoring.'
|
||||||
|
test_syntax_error 'PROGRAM==i"b"' "Invalid prefix 'i' for PROGRAM."
|
||||||
test_syntax_error 'IMPORT="b"' 'Invalid attribute for IMPORT.'
|
test_syntax_error 'IMPORT="b"' 'Invalid attribute for IMPORT.'
|
||||||
test_syntax_error 'IMPORT{a}="b"' 'Invalid attribute for IMPORT.'
|
test_syntax_error 'IMPORT{a}="b"' 'Invalid attribute for IMPORT.'
|
||||||
test_syntax_error 'IMPORT{a}-="b"' 'Invalid operator for IMPORT.'
|
test_syntax_error 'IMPORT{a}-="b"' 'Invalid operator for IMPORT.'
|
||||||
test_syntax_error 'IMPORT{file}=="%", NAME="b"' 'Invalid value "%" for IMPORT (char 1: invalid substitution type), ignoring.'
|
test_syntax_error 'IMPORT{file}=="%", NAME="b"' 'Invalid value "%" for IMPORT (char 1: invalid substitution type), ignoring.'
|
||||||
|
test_syntax_error 'IMPORT{file}==i"a", NAME="b"' "Invalid prefix 'i' for IMPORT."
|
||||||
test_syntax_error 'IMPORT{builtin}!="foo"' 'Unknown builtin command: foo'
|
test_syntax_error 'IMPORT{builtin}!="foo"' 'Unknown builtin command: foo'
|
||||||
test_syntax_error 'RESULT{a}=="b"' 'Invalid attribute for RESULT.'
|
test_syntax_error 'RESULT{a}=="b"' 'Invalid attribute for RESULT.'
|
||||||
test_syntax_error 'RESULT:="b"' 'Invalid operator for RESULT.'
|
test_syntax_error 'RESULT:="b"' 'Invalid operator for RESULT.'
|
||||||
|
|
|
@ -9,26 +9,39 @@ set -o pipefail
|
||||||
export SYSTEMD_LOG_LEVEL=debug
|
export SYSTEMD_LOG_LEVEL=debug
|
||||||
|
|
||||||
c='
|
c='
|
||||||
d /tmp/somedir
|
d$ /tmp/somedir
|
||||||
f /tmp/somedir/somefile - - - - baz
|
f$ /tmp/somedir/somefile - - - - baz
|
||||||
|
f /tmp/someotherfile - - - - qux
|
||||||
'
|
'
|
||||||
|
|
||||||
systemd-tmpfiles --create - <<<"$c"
|
systemd-tmpfiles --create - <<<"$c"
|
||||||
test -f /tmp/somedir/somefile
|
test -f /tmp/somedir/somefile
|
||||||
grep -q baz /tmp/somedir/somefile
|
grep -q baz /tmp/somedir/somefile
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
systemd-tmpfiles --purge --dry-run - <<<"$c"
|
systemd-tmpfiles --purge --dry-run - <<<"$c"
|
||||||
test -f /tmp/somedir/somefile
|
test -f /tmp/somedir/somefile
|
||||||
grep -q baz /tmp/somedir/somefile
|
grep -q baz /tmp/somedir/somefile
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
systemd-tmpfiles --purge - <<<"$c"
|
systemd-tmpfiles --purge - <<<"$c"
|
||||||
test ! -f /tmp/somedir/somefile
|
test ! -f /tmp/somedir/somefile
|
||||||
test ! -d /tmp/somedir/
|
test ! -d /tmp/somedir/
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
systemd-tmpfiles --create --purge --dry-run - <<<"$c"
|
systemd-tmpfiles --create --purge --dry-run - <<<"$c"
|
||||||
test ! -f /tmp/somedir/somefile
|
test ! -f /tmp/somedir/somefile
|
||||||
test ! -d /tmp/somedir/
|
test ! -d /tmp/somedir/
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
systemd-tmpfiles --create --purge - <<<"$c"
|
systemd-tmpfiles --create --purge - <<<"$c"
|
||||||
test -f /tmp/somedir/somefile
|
test -f /tmp/somedir/somefile
|
||||||
grep -q baz /tmp/somedir/somefile
|
grep -q baz /tmp/somedir/somefile
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
|
systemd-tmpfiles --purge - <<<"$c"
|
||||||
|
test ! -f /tmp/somedir/somefile
|
||||||
|
test ! -d /tmp/somedir/
|
||||||
|
grep -q qux /tmp/someotherfile
|
||||||
|
|
||||||
|
rm /tmp/someotherfile
|
||||||
|
|
|
@ -8,5 +8,5 @@
|
||||||
# See tmpfiles.d(5) for details
|
# See tmpfiles.d(5) for details
|
||||||
|
|
||||||
{% if LINK_SHELL_EXTRA_DROPIN %}
|
{% if LINK_SHELL_EXTRA_DROPIN %}
|
||||||
L {{SHELLPROFILEDIR}}/70-systemd-shell-extra.sh - - - - {{LIBEXECDIR}}/profile.d/70-systemd-shell-extra.sh
|
L$ {{SHELLPROFILEDIR}}/70-systemd-shell-extra.sh - - - - {{LIBEXECDIR}}/profile.d/70-systemd-shell-extra.sh
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
# See tmpfiles.d(5) for details
|
# See tmpfiles.d(5) for details
|
||||||
|
|
||||||
{% if LINK_SSH_PROXY_DROPIN %}
|
{% if LINK_SSH_PROXY_DROPIN %}
|
||||||
L {{SSHCONFDIR}}/20-systemd-ssh-proxy.conf - - - - {{LIBEXECDIR}}/ssh_config.d/20-systemd-ssh-proxy.conf
|
L$ {{SSHCONFDIR}}/20-systemd-ssh-proxy.conf - - - - {{LIBEXECDIR}}/ssh_config.d/20-systemd-ssh-proxy.conf
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if CREATE_SSHDPRIVSEPDIR %}
|
{% if CREATE_SSHDPRIVSEPDIR %}
|
||||||
d {{SSHDPRIVSEPDIR}} 0755
|
d {{SSHDPRIVSEPDIR}} 0755
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
d /run/lock 0755 root root -
|
d /run/lock 0755 root root -
|
||||||
L /var/lock - - - - ../run/lock
|
L /var/lock - - - - ../run/lock
|
||||||
{% if CREATE_LOG_DIRS %}
|
{% if CREATE_LOG_DIRS %}
|
||||||
L /var/log/README - - - - ../..{{DOC_DIR}}/README.logs
|
L$ /var/log/README - - - - ../..{{DOC_DIR}}/README.logs
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
# /run/lock/subsys is used for serializing SysV service execution, and
|
# /run/lock/subsys is used for serializing SysV service execution, and
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
# See tmpfiles.d(5) for details
|
# See tmpfiles.d(5) for details
|
||||||
|
|
||||||
d /run/systemd/netif 0755 systemd-network systemd-network -
|
d$ /run/systemd/netif 0755 systemd-network systemd-network -
|
||||||
d /run/systemd/netif/links 0755 systemd-network systemd-network -
|
d$ /run/systemd/netif/links 0755 systemd-network systemd-network -
|
||||||
d /run/systemd/netif/leases 0755 systemd-network systemd-network -
|
d$ /run/systemd/netif/leases 0755 systemd-network systemd-network -
|
||||||
d /var/lib/systemd/network 0755 systemd-network systemd-network -
|
d$ /var/lib/systemd/network 0755 systemd-network systemd-network -
|
||||||
|
|
|
@ -19,5 +19,5 @@ Q /var/lib/machines 0700 - - -
|
||||||
# systemd-nspawn --ephemeral places snapshots) we are more strict, to
|
# systemd-nspawn --ephemeral places snapshots) we are more strict, to
|
||||||
# avoid removing unrelated temporary files.
|
# avoid removing unrelated temporary files.
|
||||||
|
|
||||||
R! /var/lib/machines/.#*
|
R!$ /var/lib/machines/.#*
|
||||||
R! /.#machine.*
|
R!$ /.#machine.*
|
||||||
|
|
|
@ -14,10 +14,10 @@ x /var/tmp/systemd-private-%b-*
|
||||||
X /var/tmp/systemd-private-%b-*/tmp
|
X /var/tmp/systemd-private-%b-*/tmp
|
||||||
|
|
||||||
# Remove top-level private temporary directories on each boot
|
# Remove top-level private temporary directories on each boot
|
||||||
R! /tmp/systemd-private-*
|
R!$ /tmp/systemd-private-*
|
||||||
R! /var/tmp/systemd-private-*
|
R!$ /var/tmp/systemd-private-*
|
||||||
|
|
||||||
# Handle lost systemd-coredump temp files. They could be lost on old filesystems,
|
# Handle lost systemd-coredump temp files. They could be lost on old filesystems,
|
||||||
# for example, after hard reboot.
|
# for example, after hard reboot.
|
||||||
x /var/lib/systemd/coredump/.#core*.%b*
|
x /var/lib/systemd/coredump/.#core*.%b*
|
||||||
r! /var/lib/systemd/coredump/.#*
|
r!$ /var/lib/systemd/coredump/.#*
|
||||||
|
|
|
@ -13,11 +13,11 @@ f+! /run/utmp 0664 root utmp -
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
d /run/systemd/ask-password 0755 root root -
|
d /run/systemd/ask-password 0755 root root -
|
||||||
d /run/systemd/seats 0755 root root -
|
d$ /run/systemd/seats 0755 root root -
|
||||||
d /run/systemd/sessions 0755 root root -
|
d$ /run/systemd/sessions 0755 root root -
|
||||||
d /run/systemd/users 0755 root root -
|
d$ /run/systemd/users 0755 root root -
|
||||||
d /run/systemd/machines 0755 root root -
|
d /run/systemd/machines 0755 root root -
|
||||||
d /run/systemd/shutdown 0755 root root -
|
d$ /run/systemd/shutdown 0755 root root -
|
||||||
|
|
||||||
d /run/log 0755 root root -
|
d /run/log 0755 root root -
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue