Compare commits
49 Commits
28ecad3075
...
e7dc5dd14f
Author | SHA1 | Date |
---|---|---|
Vishal Chillara | e7dc5dd14f | |
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 | |
Daan De Meyer | e0258ac886 | |
Lennart Poettering | a859d0d378 | |
Lennart Poettering | db15657dfb | |
Lennart Poettering | 2aa3005ad2 | |
Lennart Poettering | 90cf998875 | |
Lennart Poettering | c8d60ae79d | |
Lennart Poettering | bfcf48b842 | |
Mike Yuan | 3a41a21666 | |
Luca Boccassi | 37c2010bcf | |
Yu Watanabe | 5f5c5c48b9 | |
Daan De Meyer | 27a8a29e32 | |
Daan De Meyer | faa79a78c8 | |
Daan De Meyer | f8fa4222c9 | |
Daan De Meyer | c9c5c8d29b | |
Lennart Poettering | 1b7ef87fc1 | |
Yu Watanabe | 68fdef46a7 | |
Luca Boccassi | 680dec33f2 | |
Ronan Pigott | 32b8065e87 | |
Yu Watanabe | f921e7d6a3 | |
Yu Watanabe | d97c672be0 | |
Yu Watanabe | 60b2ddc9b7 | |
Yu Watanabe | 6c38915d35 | |
Yu Watanabe | acdfb85d97 | |
Yu Watanabe | 4f176f24d6 | |
Matthieu CHARETTE | 8ee3d4df80 | |
Mike Yuan | c7f7225f1a | |
Gregory Arenius | 3f3dc6ab84 | |
Lennart Poettering | 3f49d58920 | |
Lennart Poettering | 1e1661c5d2 | |
Lennart Poettering | dc8ed83892 | |
Lennart Poettering | 831ad06bf5 | |
Lennart Poettering | d7a6bb9891 | |
Lennart Poettering | 6a92a793ac | |
Lennart Poettering | 59b3df9bae | |
Lennart Poettering | 9de565dd5d | |
Lennart Poettering | e6c49f7f11 | |
Lennart Poettering | f3c1d7fea1 | |
Lennart Poettering | a8e912f01b |
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:
|
||||||
|
|
10
TODO
10
TODO
|
@ -130,6 +130,10 @@ Deprecations and removals:
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
|
* find a nice way to opt-in into auto-masking SIGCHLD on first
|
||||||
|
sd_event_add_child(), and then get rid of many more explicit sigprocmask()
|
||||||
|
calls.
|
||||||
|
|
||||||
* maybe set shell.prompt.prefix credential in run0 to some warning emoji,
|
* maybe set shell.prompt.prefix credential in run0 to some warning emoji,
|
||||||
i.e. ⚠️ or ☢️ or ⚡ or 👊 or 🧑🔧 or so.
|
i.e. ⚠️ or ☢️ or ⚡ or 👊 or 🧑🔧 or so.
|
||||||
|
|
||||||
|
@ -995,12 +999,6 @@ Features:
|
||||||
* in the initrd, once the rootfs encryption key has been measured to PCR 15,
|
* in the initrd, once the rootfs encryption key has been measured to PCR 15,
|
||||||
derive default machine ID to use from it, and pass it to host PID 1.
|
derive default machine ID to use from it, and pass it to host PID 1.
|
||||||
|
|
||||||
* tree-wide: convert as much as possible over to use sd_event_set_signal_exit(), instead
|
|
||||||
of manually hooking into SIGINT/SIGTERM
|
|
||||||
|
|
||||||
* tree-wide: convert as much as possible over to SD_EVENT_SIGNAL_PROCMASK
|
|
||||||
instead of manual blocking.
|
|
||||||
|
|
||||||
* sd-boot: for each installed OS, grey out older entries (i.e. all but the
|
* sd-boot: for each installed OS, grey out older entries (i.e. all but the
|
||||||
newest), to indicate they are obsolete
|
newest), to indicate they are obsolete
|
||||||
|
|
||||||
|
|
|
@ -299,6 +299,10 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svnCHUWIInnovationAndTechnology*:pnHi10X:*
|
||||||
sensor:modalias:acpi:MXC6655*:dmi:*:svnCHUWIINNOVATIONLIMITED:pnHi10Go:*
|
sensor:modalias:acpi:MXC6655*:dmi:*:svnCHUWIINNOVATIONLIMITED:pnHi10Go:*
|
||||||
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0,-1, 0; 0, 0, 1
|
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0,-1, 0; 0, 0, 1
|
||||||
|
|
||||||
|
# Chuwi Hi10 Max
|
||||||
|
sensor:modalias:acpi:MXC6655*:dmi:*:svnCHUWIInnovationAndTechnology*:pnHi10Max:*
|
||||||
|
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
# Chuwi Hi12
|
# Chuwi Hi12
|
||||||
sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo:pnP02BD6_HI-122LP:*
|
sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo:pnP02BD6_HI-122LP:*
|
||||||
sensor:modalias:acpi:BOSC0200*:dmi:*:svnDefaultstring:pnDefaultstring:*
|
sensor:modalias:acpi:BOSC0200*:dmi:*:svnDefaultstring:pnDefaultstring:*
|
||||||
|
@ -603,6 +607,15 @@ sensor:modalias:i2c:bmc150_accel:dmi:*:svnHewlett-Packard:pnHPPavilionx2Detachab
|
||||||
sensor:modalias:i2c:bmc150_accel:dmi:*:svnHewlett-Packard:pnHPProTablet408:*:rn8048:*
|
sensor:modalias:i2c:bmc150_accel:dmi:*:svnHewlett-Packard:pnHPProTablet408:*:rn8048:*
|
||||||
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# HUAWEI
|
||||||
|
#########################################
|
||||||
|
|
||||||
|
# HUAWEI MateBook D 15 AMD
|
||||||
|
sensor:modalias:acpi:SMO8840*:dmi:*:svnHUAWEI:pnBOHK-WAX9X:*
|
||||||
|
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
|
||||||
|
ACCEL_LOCATION=base
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
# I.T.Works
|
# I.T.Works
|
||||||
#########################################
|
#########################################
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -46,11 +46,10 @@
|
||||||
the root file system, which is then responsible for probing all remaining hardware, mounting all
|
the root file system, which is then responsible for probing all remaining hardware, mounting all
|
||||||
necessary file systems and spawning all configured services.</para>
|
necessary file systems and spawning all configured services.</para>
|
||||||
|
|
||||||
<para>On shutdown, the system manager stops all services, unmounts
|
<para>On shutdown, the system manager stops all services, unmounts all non-busy file systems (detaching
|
||||||
all file systems (detaching the storage technologies backing
|
the storage technologies backing them), and then (optionally) jumps into the exitrd, which is backed by
|
||||||
them), and then (optionally) jumps back into the initrd code which
|
tmpfs, and unmounts/detaches the remaining file systems, including the real root. As a last step,
|
||||||
unmounts/detaches the root file system and the storage it resides
|
the system is powered down.</para>
|
||||||
on. As a last step, the system is powered down.</para>
|
|
||||||
|
|
||||||
<para>Additional information about the system boot process may be
|
<para>Additional information about the system boot process may be
|
||||||
found in
|
found in
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -58,9 +58,6 @@ OPTIONS=(
|
||||||
)
|
)
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Linting the PKGBUILD takes multiple seconds every build so avoid that by nuking all the linting functions.
|
|
||||||
rm /usr/share/makepkg/lint_pkgbuild/*
|
|
||||||
|
|
||||||
TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
|
TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
|
||||||
|
|
||||||
sed --in-place "pkg/$PKG_SUBDIR/PKGBUILD" \
|
sed --in-place "pkg/$PKG_SUBDIR/PKGBUILD" \
|
||||||
|
@ -68,9 +65,11 @@ sed --in-place "pkg/$PKG_SUBDIR/PKGBUILD" \
|
||||||
--expression "s/^pkgrel=.*/pkgrel=$(date "+%Y%m%d%H%M%S" --date "@$TS")/"
|
--expression "s/^pkgrel=.*/pkgrel=$(date "+%Y%m%d%H%M%S" --date "@$TS")/"
|
||||||
|
|
||||||
# We get around makepkg's root check by setting EUID to something else.
|
# We get around makepkg's root check by setting EUID to something else.
|
||||||
|
# Linting the PKGBUILD takes multiple seconds every build so avoid that by nuking all the linting functions.
|
||||||
# shellcheck disable=SC2046
|
# shellcheck disable=SC2046
|
||||||
env --chdir="pkg/$PKG_SUBDIR" \
|
env --chdir="pkg/$PKG_SUBDIR" \
|
||||||
EUID=123 \
|
EUID=123 \
|
||||||
|
MAKEPKG_LINT_PKGBUILD=0 \
|
||||||
makepkg \
|
makepkg \
|
||||||
--noextract \
|
--noextract \
|
||||||
--noprepare \
|
--noprepare \
|
||||||
|
|
|
@ -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
|
||||||
|
@ -247,7 +253,7 @@ const char* const systemd_features =
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
static char *systemd_features_with_color(void) {
|
static char* systemd_features_with_color(void) {
|
||||||
const char *p = systemd_features;
|
const char *p = systemd_features;
|
||||||
_cleanup_free_ char *ret = NULL;
|
_cleanup_free_ char *ret = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
*ret = x;
|
if (ret)
|
||||||
|
*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, '\\', '/');
|
||||||
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ int sigaction_many_internal(const struct sigaction *sa, ...);
|
||||||
int sigset_add_many_internal(sigset_t *ss, ...);
|
int sigset_add_many_internal(sigset_t *ss, ...);
|
||||||
#define sigset_add_many(...) sigset_add_many_internal(__VA_ARGS__, -1)
|
#define sigset_add_many(...) sigset_add_many_internal(__VA_ARGS__, -1)
|
||||||
|
|
||||||
int sigprocmask_many_internal(int how, sigset_t *old, ...);
|
int sigprocmask_many_internal(int how, sigset_t *ret_old_mask, ...);
|
||||||
#define sigprocmask_many(...) sigprocmask_many_internal(__VA_ARGS__, -1)
|
#define sigprocmask_many(...) sigprocmask_many_internal(__VA_ARGS__, -1)
|
||||||
|
|
||||||
const char* signal_to_string(int i) _const_;
|
const char* signal_to_string(int i) _const_;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
|
if (loader) {
|
||||||
printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal());
|
printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
|
||||||
|
printf(" Product: %s%s%s\n", ansi_highlight(), loader, ansi_normal());
|
||||||
|
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);
|
||||||
|
|
||||||
for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
|
sd_id128_t loader_partition_uuid;
|
||||||
print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
|
bool have_loader_partition_uuid = efi_loader_get_device_part_uuid(&loader_partition_uuid) >= 0;
|
||||||
|
|
||||||
sd_id128_t bootloader_esp_uuid;
|
print_yes_no_line(false, have_loader_partition_uuid, "Boot loader set ESP information");
|
||||||
bool have_bootloader_esp_uuid = efi_loader_get_device_part_uuid(&bootloader_esp_uuid) >= 0;
|
|
||||||
|
|
||||||
print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP information");
|
if (current_entry)
|
||||||
if (have_bootloader_esp_uuid && !sd_id128_is_null(esp_uuid) &&
|
printf("Current Entry: %s\n", current_entry);
|
||||||
!sd_id128_equal(esp_uuid, bootloader_esp_uuid))
|
if (default_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("Default Entry: %s\n", default_entry);
|
||||||
SD_ID128_FORMAT_VAL(bootloader_esp_uuid),
|
if (oneshot_entry && !streq_ptr(oneshot_entry, default_entry))
|
||||||
SD_ID128_FORMAT_VAL(esp_uuid));
|
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);
|
||||||
|
|
||||||
|
sd_id128_t stub_partition_uuid;
|
||||||
|
bool have_stub_partition_uuid = efi_stub_get_device_part_uuid(&stub_partition_uuid) >= 0;
|
||||||
|
|
||||||
|
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
|
||||||
|
printf(" Partition: n/a\n");
|
||||||
|
printf(" Stub: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(stub_path));
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
if (!sd_id128_is_null(loader_part_uuid))
|
|
||||||
printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
|
||||||
SD_ID128_FORMAT_VAL(loader_part_uuid));
|
|
||||||
else
|
|
||||||
printf(" ESP: n/a\n");
|
|
||||||
printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
|
|
||||||
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);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "initrd.h"
|
#include "initrd.h"
|
||||||
#include "linux.h"
|
#include "linux.h"
|
||||||
#include "measure.h"
|
#include "measure.h"
|
||||||
|
#include "memory-util-fundamental.h"
|
||||||
#include "part-discovery.h"
|
#include "part-discovery.h"
|
||||||
#include "pe.h"
|
#include "pe.h"
|
||||||
#include "proto/block-io.h"
|
#include "proto/block-io.h"
|
||||||
|
@ -2420,18 +2421,18 @@ static EFI_STATUS initrd_prepare(
|
||||||
EFI_FILE *root,
|
EFI_FILE *root,
|
||||||
const BootEntry *entry,
|
const BootEntry *entry,
|
||||||
char16_t **ret_options,
|
char16_t **ret_options,
|
||||||
void **ret_initrd,
|
Pages *ret_initrd_pages,
|
||||||
size_t *ret_initrd_size) {
|
size_t *ret_initrd_size) {
|
||||||
|
|
||||||
assert(root);
|
assert(root);
|
||||||
assert(entry);
|
assert(entry);
|
||||||
assert(ret_options);
|
assert(ret_options);
|
||||||
assert(ret_initrd);
|
assert(ret_initrd_pages);
|
||||||
assert(ret_initrd_size);
|
assert(ret_initrd_size);
|
||||||
|
|
||||||
if (entry->type != LOADER_LINUX || !entry->initrd) {
|
if (entry->type != LOADER_LINUX || !entry->initrd) {
|
||||||
*ret_options = NULL;
|
*ret_options = NULL;
|
||||||
*ret_initrd = NULL;
|
*ret_initrd_pages = (Pages) {};
|
||||||
*ret_initrd_size = 0;
|
*ret_initrd_size = 0;
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2445,7 +2446,6 @@ static EFI_STATUS initrd_prepare(
|
||||||
|
|
||||||
EFI_STATUS err;
|
EFI_STATUS err;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
_cleanup_free_ uint8_t *initrd = NULL;
|
|
||||||
|
|
||||||
STRV_FOREACH(i, entry->initrd) {
|
STRV_FOREACH(i, entry->initrd) {
|
||||||
_cleanup_free_ char16_t *o = options;
|
_cleanup_free_ char16_t *o = options;
|
||||||
|
@ -2464,30 +2464,58 @@ static EFI_STATUS initrd_prepare(
|
||||||
if (err != EFI_SUCCESS)
|
if (err != EFI_SUCCESS)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
if (!ADD_SAFE(&size, size, ALIGN4(info->FileSize)))
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_pages_ Pages pages = xmalloc_pages(
|
||||||
|
AllocateMaxAddress,
|
||||||
|
EfiLoaderData,
|
||||||
|
EFI_SIZE_TO_PAGES(size),
|
||||||
|
UINT32_MAX /* Below 4G boundary. */);
|
||||||
|
uint8_t *p = PHYSICAL_ADDRESS_TO_POINTER(pages.addr);
|
||||||
|
|
||||||
|
STRV_FOREACH(i, entry->initrd) {
|
||||||
|
_cleanup_(file_closep) EFI_FILE *handle = NULL;
|
||||||
|
err = root->Open(root, &handle, *i, EFI_FILE_MODE_READ, 0);
|
||||||
|
if (err != EFI_SUCCESS)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
_cleanup_free_ EFI_FILE_INFO *info = NULL;
|
||||||
|
err = get_file_info(handle, &info, NULL);
|
||||||
|
if (err != EFI_SUCCESS)
|
||||||
|
return err;
|
||||||
|
|
||||||
if (info->FileSize == 0) /* Automatically skip over empty files */
|
if (info->FileSize == 0) /* Automatically skip over empty files */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
size_t new_size, read_size = info->FileSize;
|
size_t read_size = info->FileSize;
|
||||||
if (!ADD_SAFE(&new_size, size, read_size))
|
err = chunked_read(handle, &read_size, p);
|
||||||
return EFI_OUT_OF_RESOURCES;
|
|
||||||
initrd = xrealloc(initrd, size, new_size);
|
|
||||||
|
|
||||||
err = chunked_read(handle, &read_size, initrd + size);
|
|
||||||
if (err != EFI_SUCCESS)
|
if (err != EFI_SUCCESS)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
/* Make sure the actual read size is what we expected. */
|
/* Make sure the actual read size is what we expected. */
|
||||||
assert(size + read_size == new_size);
|
assert(read_size == info->FileSize);
|
||||||
size = new_size;
|
p += read_size;
|
||||||
|
|
||||||
|
size_t pad;
|
||||||
|
pad = ALIGN4(read_size) - read_size;
|
||||||
|
if (pad == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
memzero(p, pad);
|
||||||
|
p += pad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + size) == p);
|
||||||
|
|
||||||
if (entry->options) {
|
if (entry->options) {
|
||||||
_cleanup_free_ char16_t *o = options;
|
_cleanup_free_ char16_t *o = options;
|
||||||
options = xasprintf("%ls %ls", o, entry->options);
|
options = xasprintf("%ls %ls", o, entry->options);
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret_options = TAKE_PTR(options);
|
*ret_options = TAKE_PTR(options);
|
||||||
*ret_initrd = TAKE_PTR(initrd);
|
*ret_initrd_pages = TAKE_STRUCT(pages);
|
||||||
*ret_initrd_size = size;
|
*ret_initrd_size = size;
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2517,9 +2545,9 @@ static EFI_STATUS image_start(
|
||||||
return log_error_status(err, "Error making file device path: %m");
|
return log_error_status(err, "Error making file device path: %m");
|
||||||
|
|
||||||
size_t initrd_size = 0;
|
size_t initrd_size = 0;
|
||||||
_cleanup_free_ void *initrd = NULL;
|
_cleanup_pages_ Pages initrd_pages = {};
|
||||||
_cleanup_free_ char16_t *options_initrd = NULL;
|
_cleanup_free_ char16_t *options_initrd = NULL;
|
||||||
err = initrd_prepare(image_root, entry, &options_initrd, &initrd, &initrd_size);
|
err = initrd_prepare(image_root, entry, &options_initrd, &initrd_pages, &initrd_size);
|
||||||
if (err != EFI_SUCCESS)
|
if (err != EFI_SUCCESS)
|
||||||
return log_error_status(err, "Error preparing initrd: %m");
|
return log_error_status(err, "Error preparing initrd: %m");
|
||||||
|
|
||||||
|
@ -2537,7 +2565,7 @@ static EFI_STATUS image_start(
|
||||||
}
|
}
|
||||||
|
|
||||||
_cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
|
_cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
|
||||||
err = initrd_register(initrd, initrd_size, &initrd_handle);
|
err = initrd_register(PHYSICAL_ADDRESS_TO_POINTER(initrd_pages.addr), initrd_size, &initrd_handle);
|
||||||
if (err != EFI_SUCCESS)
|
if (err != EFI_SUCCESS)
|
||||||
return log_error_status(err, "Error registering initrd: %m");
|
return log_error_status(err, "Error registering initrd: %m");
|
||||||
|
|
||||||
|
|
|
@ -134,9 +134,8 @@ static EFI_STATUS combine_initrds(
|
||||||
|
|
||||||
assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + n) == p);
|
assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + n) == p);
|
||||||
|
|
||||||
*ret_initrd_pages = pages;
|
*ret_initrd_pages = TAKE_STRUCT(pages);
|
||||||
*ret_initrd_size = n;
|
*ret_initrd_size = n;
|
||||||
pages.n_pages = 0;
|
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2728,6 +2728,7 @@ int config_parse_environ(
|
||||||
COMMON_CREDS_SPECIFIERS(ltype),
|
COMMON_CREDS_SPECIFIERS(ltype),
|
||||||
{ 'h', specifier_user_home, NULL },
|
{ 'h', specifier_user_home, NULL },
|
||||||
{ 's', specifier_user_shell, NULL },
|
{ 's', specifier_user_shell, NULL },
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const char *p = rvalue;; ) {
|
for (const char *p = rvalue;; ) {
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "sd-varlink.h"
|
#include "sd-varlink.h"
|
||||||
|
|
||||||
#include "build.h"
|
#include "build.h"
|
||||||
#include "build-path.h"
|
|
||||||
#include "bus-polkit.h"
|
#include "bus-polkit.h"
|
||||||
#include "creds-util.h"
|
#include "creds-util.h"
|
||||||
#include "dirent-util.h"
|
#include "dirent-util.h"
|
||||||
|
@ -70,11 +69,11 @@ STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_signature, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_signature, freep);
|
||||||
|
|
||||||
static const char* transcode_mode_table[_TRANSCODE_MAX] = {
|
static const char* transcode_mode_table[_TRANSCODE_MAX] = {
|
||||||
[TRANSCODE_OFF] = "off",
|
[TRANSCODE_OFF] = "off",
|
||||||
[TRANSCODE_BASE64] = "base64",
|
[TRANSCODE_BASE64] = "base64",
|
||||||
[TRANSCODE_UNBASE64] = "unbase64",
|
[TRANSCODE_UNBASE64] = "unbase64",
|
||||||
[TRANSCODE_HEX] = "hex",
|
[TRANSCODE_HEX] = "hex",
|
||||||
[TRANSCODE_UNHEX] = "unhex",
|
[TRANSCODE_UNHEX] = "unhex",
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(transcode_mode, TranscodeMode);
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(transcode_mode, TranscodeMode);
|
||||||
|
@ -715,9 +714,9 @@ static int verb_help(int argc, char **argv, void *userdata) {
|
||||||
" ciphertext credential file\n"
|
" ciphertext credential file\n"
|
||||||
" decrypt INPUT [OUTPUT] Decrypt ciphertext credential file and write to\n"
|
" decrypt INPUT [OUTPUT] Decrypt ciphertext credential file and write to\n"
|
||||||
" plaintext credential file\n"
|
" plaintext credential file\n"
|
||||||
|
"\n%3$sOptions:%4$s\n"
|
||||||
" -h --help Show this help\n"
|
" -h --help Show this help\n"
|
||||||
" --version Show package version\n"
|
" --version Show package version\n"
|
||||||
"\n%3$sOptions:%4$s\n"
|
|
||||||
" --no-pager Do not pipe output into a pager\n"
|
" --no-pager Do not pipe output into a pager\n"
|
||||||
" --no-legend Do not show the headers and footers\n"
|
" --no-legend Do not show the headers and footers\n"
|
||||||
" --json=pretty|short|off\n"
|
" --json=pretty|short|off\n"
|
||||||
|
@ -1047,7 +1046,7 @@ static int creds_main(int argc, char *argv[]) {
|
||||||
{ "decrypt", 2, 3, 0, verb_decrypt },
|
{ "decrypt", 2, 3, 0, verb_decrypt },
|
||||||
{ "setup", VERB_ANY, 1, 0, verb_setup },
|
{ "setup", VERB_ANY, 1, 0, verb_setup },
|
||||||
{ "help", VERB_ANY, 1, 0, verb_help },
|
{ "help", VERB_ANY, 1, 0, verb_help },
|
||||||
{ "has-tpm2", VERB_ANY, 1, 0, verb_has_tpm2 },
|
{ "has-tpm2", VERB_ANY, 1, 0, verb_has_tpm2 }, /* for backward compatibility */
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,3 +31,25 @@ static inline bool unified_section_measure(UnifiedSection section) {
|
||||||
|
|
||||||
/* Max number of profiles per UKI */
|
/* Max number of profiles per UKI */
|
||||||
#define UNIFIED_PROFILES_MAX 256U
|
#define UNIFIED_PROFILES_MAX 256U
|
||||||
|
|
||||||
|
/* The native PE machine type, if known, for a full list see:
|
||||||
|
* https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types */
|
||||||
|
#ifndef _IMAGE_FILE_MACHINE_NATIVE
|
||||||
|
# if defined(__x86_64__)
|
||||||
|
# define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x8664)
|
||||||
|
# elif defined(__i386__)
|
||||||
|
# define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x014c)
|
||||||
|
# elif defined(__ia64__)
|
||||||
|
# define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x0200)
|
||||||
|
# elif defined(__aarch64__)
|
||||||
|
# define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0xaa64)
|
||||||
|
# elif defined(__arm__)
|
||||||
|
# define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x01c0)
|
||||||
|
# elif defined(__riscv)
|
||||||
|
# if __SIZEOF_POINTER__ == 4
|
||||||
|
# define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x5032)
|
||||||
|
# elif __SIZEOF_POINTER__ == 8
|
||||||
|
# define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x5064)
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
|
@ -222,20 +222,16 @@ int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
r = sd_event_set_signal_exit(m->event, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
r = sd_event_add_memory_pressure(m->event, /* ret_event_source= */ NULL, /* callback= */ NULL, /* userdata= */ NULL);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_add_memory_pressure(m->event, NULL, NULL, NULL);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) || ERRNO_IS_PRIVILEGE(r) || (r == -EHOSTDOWN) ? LOG_DEBUG : LOG_WARNING, r,
|
log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) || ERRNO_IS_PRIVILEGE(r) || (r == -EHOSTDOWN) ? LOG_DEBUG : LOG_WARNING, r,
|
||||||
"Failed to allocate memory pressure watch, ignoring: %m");
|
"Failed to allocate memory pressure watch, ignoring: %m");
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGRTMIN+18, sigrtmin18_handler, NULL);
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata = */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
umask(0022);
|
umask(0022);
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
|
||||||
|
|
||||||
r = manager_new(&m);
|
r = manager_new(&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -1787,17 +1787,15 @@ static int server_setup_signals(Server *s) {
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+18) >= 0);
|
r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigusr1, s);
|
||||||
|
|
||||||
r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(s->event, &s->sigusr2_event_source, SIGUSR2, dispatch_sigusr2, s);
|
r = sd_event_add_signal(s->event, &s->sigusr2_event_source, SIGUSR2|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigusr2, s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(s->event, &s->sigterm_event_source, SIGTERM, dispatch_sigterm, s);
|
r = sd_event_add_signal(s->event, &s->sigterm_event_source, SIGTERM|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigterm, s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1808,7 +1806,7 @@ static int server_setup_signals(Server *s) {
|
||||||
|
|
||||||
/* When journald is invoked on the terminal (when debugging), it's useful if C-c is handled
|
/* When journald is invoked on the terminal (when debugging), it's useful if C-c is handled
|
||||||
* equivalent to SIGTERM. */
|
* equivalent to SIGTERM. */
|
||||||
r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s);
|
r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigterm, s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1819,7 +1817,7 @@ static int server_setup_signals(Server *s) {
|
||||||
/* SIGRTMIN+1 causes an immediate sync. We process this very late, so that everything else queued at
|
/* SIGRTMIN+1 causes an immediate sync. We process this very late, so that everything else queued at
|
||||||
* this point is really written to disk. Clients can watch /run/systemd/journal/synced with inotify
|
* this point is really written to disk. Clients can watch /run/systemd/journal/synced with inotify
|
||||||
* until its mtime changes to see when a sync happened. */
|
* until its mtime changes to see when a sync happened. */
|
||||||
r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+1, dispatch_sigrtmin1, s);
|
r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, (SIGRTMIN+1)|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigrtmin1, s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1827,7 +1825,7 @@ static int server_setup_signals(Server *s) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(s->event, NULL, SIGRTMIN+18, sigrtmin18_handler, &s->sigrtmin18_info);
|
r = sd_event_add_signal(s->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, &s->sigrtmin18_info);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -86,15 +86,11 @@ static int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
r = sd_event_set_signal_exit(m->event, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata= */ NULL);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGRTMIN+18, sigrtmin18_handler, NULL);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -826,7 +822,7 @@ static int manager_connect_console(Manager *m) {
|
||||||
return log_error_errno(r, "Failed to watch foreground console: %m");
|
return log_error_errno(r, "Failed to watch foreground console: %m");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIGRTMIN is used as global VT-release signal, SIGRTMIN + 1 is used
|
* SIGRTMIN + 0 is used as global VT-release signal, SIGRTMIN + 1 is used
|
||||||
* as VT-acquire signal. We ignore any acquire-events (yes, we still
|
* as VT-acquire signal. We ignore any acquire-events (yes, we still
|
||||||
* have to provide a valid signal-number for it!) and acknowledge all
|
* have to provide a valid signal-number for it!) and acknowledge all
|
||||||
* release events immediately.
|
* release events immediately.
|
||||||
|
@ -838,11 +834,10 @@ static int manager_connect_console(Manager *m) {
|
||||||
SIGRTMIN, SIGRTMAX);
|
SIGRTMIN, SIGRTMAX);
|
||||||
|
|
||||||
assert_se(ignore_signals(SIGRTMIN + 1) >= 0);
|
assert_se(ignore_signals(SIGRTMIN + 1) >= 0);
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN) >= 0);
|
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m);
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN + 0) | SD_EVENT_SIGNAL_PROCMASK, manager_vt_switch, m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to subscribe to signal: %m");
|
return log_error_errno(r, "Failed to subscribe to SIGRTMIN+0 signal: %m");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1097,7 +1092,7 @@ static int manager_startup(Manager *m) {
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGHUP, manager_dispatch_reload_signal, m);
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, SIGHUP|SD_EVENT_SIGNAL_PROCMASK, manager_dispatch_reload_signal, m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to register SIGHUP handler: %m");
|
return log_error_errno(r, "Failed to register SIGHUP handler: %m");
|
||||||
|
|
||||||
|
@ -1247,7 +1242,7 @@ static int run(int argc, char *argv[]) {
|
||||||
(void) mkdir_label("/run/systemd/users", 0755);
|
(void) mkdir_label("/run/systemd/users", 0755);
|
||||||
(void) mkdir_label("/run/systemd/sessions", 0755);
|
(void) mkdir_label("/run/systemd/sessions", 0755);
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGHUP, SIGTERM, SIGINT, SIGCHLD, SIGRTMIN+18) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
|
||||||
|
|
||||||
r = manager_new(&m);
|
r = manager_new(&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -1220,8 +1220,6 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, PT
|
||||||
assert(master >= 0);
|
assert(master >= 0);
|
||||||
assert(name);
|
assert(name);
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT) >= 0);
|
|
||||||
|
|
||||||
if (!arg_quiet) {
|
if (!arg_quiet) {
|
||||||
if (streq(name, ".host"))
|
if (streq(name, ".host"))
|
||||||
log_info("Connected to the local host. Press ^] three times within 1s to exit session.");
|
log_info("Connected to the local host. Press ^] three times within 1s to exit session.");
|
||||||
|
@ -1229,8 +1227,9 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, PT
|
||||||
log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name);
|
log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
|
r = sd_event_set_signal_exit(event, true);
|
||||||
(void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to enable SIGINT/SITERM handling: %m");
|
||||||
|
|
||||||
r = pty_forward_new(event, master, flags, forward);
|
r = pty_forward_new(event, master, flags, forward);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -55,15 +55,11 @@ static int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
r = sd_event_set_signal_exit(m->event, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata= */ NULL);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGRTMIN+18, sigrtmin18_handler, NULL);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -332,7 +328,7 @@ static int run(int argc, char *argv[]) {
|
||||||
* make sure this check stays in. */
|
* make sure this check stays in. */
|
||||||
(void) mkdir_label("/run/systemd/machines", 0755);
|
(void) mkdir_label("/run/systemd/machines", 0755);
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
|
||||||
|
|
||||||
r = manager_new(&m);
|
r = manager_new(&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -410,8 +410,7 @@ int manager_new(Manager **ret,
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
(void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
(void) sd_event_set_signal_exit(m->event, true);
|
||||||
(void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
|
||||||
|
|
||||||
if (timeout > 0) {
|
if (timeout > 0) {
|
||||||
r = sd_event_add_time_relative(m->event, NULL, CLOCK_BOOTTIME, timeout, 0, NULL, INT_TO_PTR(-ETIMEDOUT));
|
r = sd_event_add_time_relative(m->event, NULL, CLOCK_BOOTTIME, timeout, 0, NULL, INT_TO_PTR(-ETIMEDOUT));
|
||||||
|
|
|
@ -204,8 +204,6 @@ static int run(int argc, char *argv[]) {
|
||||||
if (arg_quiet)
|
if (arg_quiet)
|
||||||
log_set_max_level(LOG_ERR);
|
log_set_max_level(LOG_ERR);
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
|
|
||||||
|
|
||||||
r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_required_family, arg_any, arg_timeout);
|
r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_required_family, arg_any, arg_timeout);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Could not create manager: %m");
|
return log_error_errno(r, "Could not create manager: %m");
|
||||||
|
|
|
@ -5601,6 +5601,10 @@ static int run_container(
|
||||||
log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
|
log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note: we do not use SD_EVENT_SIGNAL_PROCMASK or sd_event_set_signal_exit(), since we want the
|
||||||
|
* signals to be block continuously, even if we destroy the event loop and allocate a new one on
|
||||||
|
* container reboot. */
|
||||||
|
|
||||||
if (arg_kill_signal > 0) {
|
if (arg_kill_signal > 0) {
|
||||||
/* Try to kill the init system on SIGINT or SIGTERM */
|
/* Try to kill the init system on SIGINT or SIGTERM */
|
||||||
(void) sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, PID_TO_PTR(*pid));
|
(void) sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, PID_TO_PTR(*pid));
|
||||||
|
|
|
@ -657,11 +657,7 @@ int manager_new(Manager **ret) {
|
||||||
|
|
||||||
(void) sd_event_set_watchdog(m->event, true);
|
(void) sd_event_set_watchdog(m->event, true);
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
r = sd_event_set_signal_exit(m->event, true);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -167,8 +167,6 @@ static int run(int argc, char *argv[]) {
|
||||||
if (!FLAGS_SET(mask, CGROUP_MASK_MEMORY))
|
if (!FLAGS_SET(mask, CGROUP_MASK_MEMORY))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Requires the cgroup memory controller.");
|
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Requires the cgroup memory controller.");
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
|
|
||||||
|
|
||||||
if (arg_mem_pressure_usec > 0 && arg_mem_pressure_usec < 1 * USEC_PER_SEC)
|
if (arg_mem_pressure_usec > 0 && arg_mem_pressure_usec < 1 * USEC_PER_SEC)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DefaultMemoryPressureDurationSec= must be 0 or at least 1s");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DefaultMemoryPressureDurationSec= must be 0 or at least 1s");
|
||||||
|
|
||||||
|
|
|
@ -5408,7 +5408,7 @@ static int partition_populate_directory(Context *context, Partition *p, char **r
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
log_info("Populating %s filesystem.", p->format);
|
log_info("Preparing to populate %s filesystem.", p->format);
|
||||||
|
|
||||||
r = var_tmp_dir(&vt);
|
r = var_tmp_dir(&vt);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -5434,7 +5434,7 @@ static int partition_populate_directory(Context *context, Partition *p, char **r
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
log_info("Successfully populated %s filesystem.", p->format);
|
log_info("Ready to populate %s filesystem.", p->format);
|
||||||
|
|
||||||
*ret = TAKE_PTR(root);
|
*ret = TAKE_PTR(root);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -36,15 +36,11 @@ static int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
r = sd_event_set_signal_exit(m->event, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata= */ NULL);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGRTMIN+18, sigrtmin18_handler, NULL);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -142,7 +138,7 @@ static int run(int argc, char *argv[]) {
|
||||||
if (argc != 1)
|
if (argc != 1)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
|
||||||
|
|
||||||
r = manager_new(&m);
|
r = manager_new(&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -682,9 +682,9 @@ int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
(void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
r = sd_event_set_signal_exit(m->event, true);
|
||||||
(void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
if (r < 0)
|
||||||
(void) sd_event_add_signal(m->event, NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, manager_dispatch_reload_signal, m);
|
return r;
|
||||||
|
|
||||||
(void) sd_event_set_watchdog(m->event, true);
|
(void) sd_event_set_watchdog(m->event, true);
|
||||||
|
|
||||||
|
@ -720,10 +720,25 @@ int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
(void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m);
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, manager_dispatch_reload_signal, m);
|
||||||
(void) sd_event_add_signal(m->event, &m->sigusr2_event_source, SIGUSR2, manager_sigusr2, m);
|
if (r < 0)
|
||||||
(void) sd_event_add_signal(m->event, &m->sigrtmin1_event_source, SIGRTMIN+1, manager_sigrtmin1, m);
|
return log_debug_errno(r, "Failed install SIGHUP handler: %m");
|
||||||
(void) sd_event_add_signal(m->event, NULL, SIGRTMIN+18, sigrtmin18_handler, &m->sigrtmin18_info);
|
|
||||||
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, SIGUSR1 | SD_EVENT_SIGNAL_PROCMASK, manager_sigusr1, m);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed install SIGUSR1 handler: %m");
|
||||||
|
|
||||||
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, SIGUSR2 | SD_EVENT_SIGNAL_PROCMASK, manager_sigusr2, m);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed install SIGUSR2 handler: %m");
|
||||||
|
|
||||||
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN+1) | SD_EVENT_SIGNAL_PROCMASK, manager_sigrtmin1, m);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed install SIGRTMIN+1 handler: %m");
|
||||||
|
|
||||||
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN+18) | SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, &m->sigrtmin18_info);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed install SIGRTMIN+18 handler: %m");
|
||||||
|
|
||||||
manager_cleanup_saved_user(m);
|
manager_cleanup_saved_user(m);
|
||||||
|
|
||||||
|
@ -802,10 +817,6 @@ Manager *manager_free(Manager *m) {
|
||||||
|
|
||||||
sd_bus_flush_close_unref(m->bus);
|
sd_bus_flush_close_unref(m->bus);
|
||||||
|
|
||||||
sd_event_source_unref(m->sigusr1_event_source);
|
|
||||||
sd_event_source_unref(m->sigusr2_event_source);
|
|
||||||
sd_event_source_unref(m->sigrtmin1_event_source);
|
|
||||||
|
|
||||||
dns_resource_key_unref(m->llmnr_host_ipv4_key);
|
dns_resource_key_unref(m->llmnr_host_ipv4_key);
|
||||||
dns_resource_key_unref(m->llmnr_host_ipv6_key);
|
dns_resource_key_unref(m->llmnr_host_ipv6_key);
|
||||||
dns_resource_key_unref(m->mdns_host_ipv4_key);
|
dns_resource_key_unref(m->mdns_host_ipv4_key);
|
||||||
|
|
|
@ -124,10 +124,6 @@ struct Manager {
|
||||||
int hostname_fd;
|
int hostname_fd;
|
||||||
sd_event_source *hostname_event_source;
|
sd_event_source *hostname_event_source;
|
||||||
|
|
||||||
sd_event_source *sigusr1_event_source;
|
|
||||||
sd_event_source *sigusr2_event_source;
|
|
||||||
sd_event_source *sigrtmin1_event_source;
|
|
||||||
|
|
||||||
unsigned n_transactions_total;
|
unsigned n_transactions_total;
|
||||||
unsigned n_timeouts_total;
|
unsigned n_timeouts_total;
|
||||||
unsigned n_timeouts_served_stale_total;
|
unsigned n_timeouts_served_stale_total;
|
||||||
|
|
|
@ -67,8 +67,6 @@ static int run(int argc, char *argv[]) {
|
||||||
return log_error_errno(r, "Failed to drop privileges: %m");
|
return log_error_errno(r, "Failed to drop privileges: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+18) >= 0);
|
|
||||||
|
|
||||||
r = manager_new(&m);
|
r = manager_new(&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Could not create manager: %m");
|
return log_error_errno(r, "Could not create manager: %m");
|
||||||
|
|
|
@ -1875,8 +1875,6 @@ static int start_transient_service(sd_bus *bus) {
|
||||||
return log_error_errno(r, "Failed to get event loop: %m");
|
return log_error_errno(r, "Failed to get event loop: %m");
|
||||||
|
|
||||||
if (master >= 0) {
|
if (master >= 0) {
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, /* old_sigset=*/ NULL, SIGWINCH) >= 0);
|
|
||||||
|
|
||||||
(void) sd_event_set_signal_exit(c.event, true);
|
(void) sd_event_set_signal_exit(c.event, true);
|
||||||
|
|
||||||
if (!arg_quiet)
|
if (!arg_quiet)
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
|
#include "uki.h"
|
||||||
#include "unaligned.h"
|
#include "unaligned.h"
|
||||||
|
|
||||||
static const char* const boot_entry_type_table[_BOOT_ENTRY_TYPE_MAX] = {
|
static const char* const boot_entry_type_table[_BOOT_ENTRY_TYPE_MAX] = {
|
||||||
|
@ -48,6 +49,7 @@ static void boot_entry_free(BootEntry *entry) {
|
||||||
|
|
||||||
free(entry->id);
|
free(entry->id);
|
||||||
free(entry->id_old);
|
free(entry->id_old);
|
||||||
|
free(entry->id_without_profile);
|
||||||
free(entry->path);
|
free(entry->path);
|
||||||
free(entry->root);
|
free(entry->root);
|
||||||
free(entry->title);
|
free(entry->title);
|
||||||
|
@ -529,10 +531,18 @@ static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = -strverscmp_improved(a->id, b->id);
|
r = -strverscmp_improved(a->id_without_profile ?: a->id, b->id_without_profile ?: b->id);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (a->id_without_profile && b->id_without_profile) {
|
||||||
|
/* The strverscmp_improved() call above already established that we are talking about the
|
||||||
|
* same image here, hence order by profile, if there is one */
|
||||||
|
r = CMP(a->profile, b->profile);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (a->tries_left != UINT_MAX || b->tries_left != UINT_MAX)
|
if (a->tries_left != UINT_MAX || b->tries_left != UINT_MAX)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -636,28 +646,30 @@ static int boot_entries_find_type1(
|
||||||
static int boot_entry_load_unified(
|
static int boot_entry_load_unified(
|
||||||
const char *root,
|
const char *root,
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *osrelease,
|
unsigned profile,
|
||||||
const char *cmdline,
|
const char *osrelease_text,
|
||||||
|
const char *profile_text,
|
||||||
|
const char *cmdline_text,
|
||||||
BootEntry *ret) {
|
BootEntry *ret) {
|
||||||
|
|
||||||
_cleanup_free_ char *fname = NULL, *os_pretty_name = NULL, *os_image_id = NULL, *os_name = NULL, *os_id = NULL,
|
_cleanup_free_ char *fname = NULL, *os_pretty_name = NULL, *os_image_id = NULL, *os_name = NULL, *os_id = NULL,
|
||||||
*os_image_version = NULL, *os_version = NULL, *os_version_id = NULL, *os_build_id = NULL;
|
*os_image_version = NULL, *os_version = NULL, *os_version_id = NULL, *os_build_id = NULL;
|
||||||
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_UNIFIED);
|
|
||||||
const char *k, *good_name, *good_version, *good_sort_key;
|
const char *k, *good_name, *good_version, *good_sort_key;
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(root);
|
assert(root);
|
||||||
assert(path);
|
assert(path);
|
||||||
assert(osrelease);
|
assert(osrelease_text);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
k = path_startswith(path, root);
|
k = path_startswith(path, root);
|
||||||
if (!k)
|
if (!k)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Path is not below root: %s", path);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Path is not below root: %s", path);
|
||||||
|
|
||||||
f = fmemopen_unlocked((void*) osrelease, strlen(osrelease), "r");
|
f = fmemopen_unlocked((void*) osrelease_text, strlen(osrelease_text), "r");
|
||||||
if (!f)
|
if (!f)
|
||||||
return log_error_errno(errno, "Failed to open os-release buffer: %m");
|
return log_oom();
|
||||||
|
|
||||||
r = parse_env_file(f, "os-release",
|
r = parse_env_file(f, "os-release",
|
||||||
"PRETTY_NAME", &os_pretty_name,
|
"PRETTY_NAME", &os_pretty_name,
|
||||||
|
@ -685,10 +697,28 @@ static int boot_entry_load_unified(
|
||||||
&good_sort_key))
|
&good_sort_key))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Missing fields in os-release data from unified kernel image %s, refusing.", path);
|
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Missing fields in os-release data from unified kernel image %s, refusing.", path);
|
||||||
|
|
||||||
|
_cleanup_free_ char *profile_id = NULL, *profile_title = NULL;
|
||||||
|
if (profile_text) {
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
f = fmemopen_unlocked((void*) profile_text, strlen(profile_text), "r");
|
||||||
|
if (!f)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = parse_env_file(
|
||||||
|
f, "profile",
|
||||||
|
"ID", &profile_id,
|
||||||
|
"TITLE", &profile_title);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse profile data from unified kernel image '%s': %m", path);
|
||||||
|
}
|
||||||
|
|
||||||
r = path_extract_filename(path, &fname);
|
r = path_extract_filename(path, &fname);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to extract file name from '%s': %m", path);
|
return log_error_errno(r, "Failed to extract file name from '%s': %m", path);
|
||||||
|
|
||||||
|
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_UNIFIED);
|
||||||
|
|
||||||
r = boot_filename_extract_tries(fname, &tmp.id, &tmp.tries_left, &tmp.tries_done);
|
r = boot_filename_extract_tries(fname, &tmp.id, &tmp.tries_left, &tmp.tries_done);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -696,6 +726,19 @@ static int boot_entry_load_unified(
|
||||||
if (!efi_loader_entry_name_valid(tmp.id))
|
if (!efi_loader_entry_name_valid(tmp.id))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry name: %s", tmp.id);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry name: %s", tmp.id);
|
||||||
|
|
||||||
|
tmp.profile = profile;
|
||||||
|
|
||||||
|
if (profile_id || profile > 0) {
|
||||||
|
tmp.id_without_profile = TAKE_PTR(tmp.id);
|
||||||
|
|
||||||
|
if (profile_id)
|
||||||
|
tmp.id = strjoin(tmp.id_without_profile, "@", profile_id);
|
||||||
|
else
|
||||||
|
(void) asprintf(&tmp.id, "%s@%u", tmp.id_without_profile, profile);
|
||||||
|
if (!tmp.id)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
if (os_id && os_version_id) {
|
if (os_id && os_version_id) {
|
||||||
tmp.id_old = strjoin(os_id, "-", os_version_id);
|
tmp.id_old = strjoin(os_id, "-", os_version_id);
|
||||||
if (!tmp.id_old)
|
if (!tmp.id_old)
|
||||||
|
@ -714,13 +757,18 @@ static int boot_entry_load_unified(
|
||||||
if (!tmp.kernel)
|
if (!tmp.kernel)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
tmp.options = strv_new(skip_leading_chars(cmdline, WHITESPACE));
|
tmp.options = strv_new(cmdline_text);
|
||||||
if (!tmp.options)
|
if (!tmp.options)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
delete_trailing_chars(tmp.options[0], WHITESPACE);
|
if (profile_title)
|
||||||
|
tmp.title = strjoin(good_name, " (", profile_title, ")");
|
||||||
tmp.title = strdup(good_name);
|
else if (profile_id)
|
||||||
|
tmp.title = strjoin(good_name, " (", profile_id, ")");
|
||||||
|
else if (profile > 0)
|
||||||
|
(void) asprintf(&tmp.title, "%s (@%u)", good_name, profile);
|
||||||
|
else
|
||||||
|
tmp.title = strdup(good_name);
|
||||||
if (!tmp.title)
|
if (!tmp.title)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
@ -740,11 +788,7 @@ static int boot_entry_load_unified(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Maximum PE section we are willing to load (Note that sections we are not interested in may be larger, but
|
static int pe_load_headers_and_sections(
|
||||||
* the ones we do care about and we are willing to load into memory have this size limit.) */
|
|
||||||
#define PE_SECTION_SIZE_MAX (4U*1024U*1024U)
|
|
||||||
|
|
||||||
static int find_sections(
|
|
||||||
int fd,
|
int fd,
|
||||||
const char *path,
|
const char *path,
|
||||||
IMAGE_SECTION_HEADER **ret_sections,
|
IMAGE_SECTION_HEADER **ret_sections,
|
||||||
|
@ -774,92 +818,177 @@ static int find_sections(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_cmdline_section(
|
static const IMAGE_SECTION_HEADER* pe_find_profile_section_table(
|
||||||
int fd,
|
const PeHeader *pe_header,
|
||||||
const char *path,
|
const IMAGE_SECTION_HEADER *sections,
|
||||||
IMAGE_SECTION_HEADER *sections,
|
unsigned profile,
|
||||||
PeHeader *pe_header,
|
size_t *ret_n_sections) {
|
||||||
char **ret_cmdline) {
|
|
||||||
|
|
||||||
int r;
|
assert(pe_header);
|
||||||
char *cmdline = NULL, *t = NULL;
|
|
||||||
_cleanup_free_ char *word = NULL;
|
|
||||||
|
|
||||||
assert(path);
|
/* Looks for the part of the section table that defines the specified profile. If 'profile' is
|
||||||
|
* specified as UINT_MAX this will look for the base profile. */
|
||||||
|
|
||||||
if (!ret_cmdline)
|
if (le16toh(pe_header->pe.NumberOfSections) == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
assert(sections);
|
||||||
|
|
||||||
|
const IMAGE_SECTION_HEADER
|
||||||
|
*p = sections,
|
||||||
|
*e = sections + le16toh(pe_header->pe.NumberOfSections),
|
||||||
|
*start = profile == UINT_MAX ? sections : NULL,
|
||||||
|
*end;
|
||||||
|
unsigned current_profile = UINT_MAX;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
p = pe_section_table_find(p, e - p, ".profile");
|
||||||
|
if (!p) {
|
||||||
|
end = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (current_profile == profile) {
|
||||||
|
end = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_profile == UINT_MAX)
|
||||||
|
current_profile = 0;
|
||||||
|
else
|
||||||
|
current_profile++;
|
||||||
|
|
||||||
|
if (current_profile == profile)
|
||||||
|
start = p;
|
||||||
|
|
||||||
|
p++; /* Continue scanning after the .profile entry we just found */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!start)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (ret_n_sections)
|
||||||
|
*ret_n_sections = end - start;
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int trim_cmdline(char **cmdline) {
|
||||||
|
assert(cmdline);
|
||||||
|
|
||||||
|
/* Strips leading and trailing whitespace from command line */
|
||||||
|
|
||||||
|
if (!*cmdline)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = pe_read_section_data(fd, pe_header, sections, ".cmdline", PE_SECTION_SIZE_MAX, (void**) &cmdline, NULL);
|
const char *skipped = skip_leading_chars(*cmdline, WHITESPACE);
|
||||||
if (r == -ENXIO) { /* cmdline is optional */
|
|
||||||
*ret_cmdline = NULL;
|
if (isempty(skipped)) {
|
||||||
|
*cmdline = mfree(*cmdline);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (r < 0)
|
|
||||||
return log_warning_errno(r, "Failed to read .cmdline section of '%s': %m", path);
|
|
||||||
|
|
||||||
word = strdup(cmdline);
|
if (skipped != *cmdline) {
|
||||||
if (!word)
|
_cleanup_free_ char *c = strdup(skipped);
|
||||||
return log_oom();
|
if (!c)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Quick test to check if there is actual content in the addon cmdline */
|
free_and_replace(*cmdline, c);
|
||||||
t = delete_chars(word, NULL);
|
}
|
||||||
if (isempty(t))
|
|
||||||
*ret_cmdline = NULL;
|
|
||||||
else
|
|
||||||
*ret_cmdline = TAKE_PTR(cmdline);
|
|
||||||
|
|
||||||
return 0;
|
delete_trailing_chars(*cmdline, WHITESPACE);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_osrel_section(
|
/* Maximum PE section we are willing to load (Note that sections we are not interested in may be larger, but
|
||||||
int fd,
|
* the ones we do care about and we are willing to load into memory have this size limit.) */
|
||||||
const char *path,
|
#define PE_SECTION_SIZE_MAX (4U*1024U*1024U)
|
||||||
IMAGE_SECTION_HEADER *sections,
|
|
||||||
PeHeader *pe_header,
|
static int pe_find_uki_sections(
|
||||||
char **ret_osrelease) {
|
|
||||||
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!ret_osrelease)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
r = pe_read_section_data(fd, pe_header, sections, ".osrel", PE_SECTION_SIZE_MAX, (void**) ret_osrelease, NULL);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to read .osrel section of '%s': %m", path);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int find_uki_sections(
|
|
||||||
int fd,
|
int fd,
|
||||||
const char *path,
|
const char *path,
|
||||||
|
unsigned profile,
|
||||||
char **ret_osrelease,
|
char **ret_osrelease,
|
||||||
|
char **ret_profile,
|
||||||
char **ret_cmdline) {
|
char **ret_cmdline) {
|
||||||
|
|
||||||
|
_cleanup_free_ char *osrelease_text = NULL, *profile_text = NULL, *cmdline_text = NULL;
|
||||||
_cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
|
_cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
|
||||||
_cleanup_free_ PeHeader *pe_header = NULL;
|
_cleanup_free_ PeHeader *pe_header = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = find_sections(fd, path, §ions, &pe_header);
|
assert(fd >= 0);
|
||||||
|
assert(path);
|
||||||
|
assert(profile != UINT_MAX);
|
||||||
|
assert(ret_osrelease);
|
||||||
|
assert(ret_profile);
|
||||||
|
assert(ret_cmdline);
|
||||||
|
|
||||||
|
r = pe_load_headers_and_sections(fd, path, §ions, &pe_header);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!pe_is_uki(pe_header, sections))
|
if (!pe_is_uki(pe_header, sections))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Parsed PE file '%s' is not a UKI.", path);
|
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Parsed PE file '%s' is not a UKI.", path);
|
||||||
|
|
||||||
r = find_osrel_section(fd, path, sections, pe_header, ret_osrelease);
|
if (!pe_is_native(pe_header)) /* Don't process non-native UKIs */
|
||||||
if (r < 0)
|
goto nothing;
|
||||||
return r;
|
|
||||||
|
|
||||||
r = find_cmdline_section(fd, path, sections, pe_header, ret_cmdline);
|
/* Find part of the section table for this profile */
|
||||||
if (r < 0)
|
size_t n_psections = 0;
|
||||||
return r;
|
const IMAGE_SECTION_HEADER *psections = pe_find_profile_section_table(pe_header, sections, profile, &n_psections);
|
||||||
|
if (!psections && profile != 0) /* Profile not found? (Profile @0 needs no explicit .profile!) */
|
||||||
|
goto nothing;
|
||||||
|
|
||||||
|
/* Find base profile part of section table */
|
||||||
|
size_t n_bsections;
|
||||||
|
const IMAGE_SECTION_HEADER *bsections = ASSERT_PTR(pe_find_profile_section_table(pe_header, sections, UINT_MAX, &n_bsections));
|
||||||
|
|
||||||
|
struct {
|
||||||
|
const char *name;
|
||||||
|
char **data;
|
||||||
|
} table[] = {
|
||||||
|
{ ".osrel", &osrelease_text },
|
||||||
|
{ ".profile", &profile_text },
|
||||||
|
{ ".cmdline", &cmdline_text },
|
||||||
|
};
|
||||||
|
|
||||||
|
FOREACH_ELEMENT(t, table) {
|
||||||
|
const IMAGE_SECTION_HEADER *found;
|
||||||
|
|
||||||
|
/* First look in the profile part of the section table, and if we don't find anything there, look into the base part */
|
||||||
|
found = pe_section_table_find(psections, n_psections, t->name);
|
||||||
|
if (!found) {
|
||||||
|
found = pe_section_table_find(bsections, n_bsections, t->name);
|
||||||
|
if (!found)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Permit "masking" of sections in the base profile */
|
||||||
|
if (found->VirtualSize == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = pe_read_section_data(fd, found, PE_SECTION_SIZE_MAX, (void**) t->data, /* ret_data= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to load contents of section '%s': %m", t->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!osrelease_text)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unified kernel image lacks .osrel data for profile @%u, refusing.", profile);
|
||||||
|
|
||||||
|
if (trim_cmdline(&cmdline_text) < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
*ret_osrelease = TAKE_PTR(osrelease_text);
|
||||||
|
*ret_profile = TAKE_PTR(profile_text);
|
||||||
|
*ret_cmdline = TAKE_PTR(cmdline_text);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
nothing:
|
||||||
|
*ret_osrelease = *ret_profile = *ret_cmdline = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_addon_sections(
|
static int pe_find_addon_sections(
|
||||||
int fd,
|
int fd,
|
||||||
const char *path,
|
const char *path,
|
||||||
char **ret_cmdline) {
|
char **ret_cmdline) {
|
||||||
|
@ -868,19 +997,39 @@ static int find_addon_sections(
|
||||||
_cleanup_free_ PeHeader *pe_header = NULL;
|
_cleanup_free_ PeHeader *pe_header = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = find_sections(fd, path, §ions, &pe_header);
|
assert(fd >= 0);
|
||||||
|
assert(path);
|
||||||
|
|
||||||
|
r = pe_load_headers_and_sections(fd, path, §ions, &pe_header);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = find_cmdline_section(fd, path, sections, pe_header, ret_cmdline);
|
if (!pe_is_addon(pe_header, sections))
|
||||||
/* If addon cmdline is empty or contains just separators,
|
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Parse PE file '%s' is not an add-on.", path);
|
||||||
* don't bother tracking it.
|
|
||||||
* Don't check r because it cannot return <0 if cmdline is empty,
|
|
||||||
* as cmdline is always optional. */
|
|
||||||
if (!ret_cmdline)
|
|
||||||
return log_warning_errno(SYNTHETIC_ERRNO(ENOENT), "Addon %s contains empty cmdline and will be therefore ignored.", path);
|
|
||||||
|
|
||||||
return r;
|
/* Define early, before the gotos below */
|
||||||
|
_cleanup_free_ char *cmdline_text = NULL;
|
||||||
|
|
||||||
|
if (!pe_is_native(pe_header))
|
||||||
|
goto nothing;
|
||||||
|
|
||||||
|
const IMAGE_SECTION_HEADER *found = pe_section_table_find(sections, le16toh(pe_header->pe.NumberOfSections), ".cmdline");
|
||||||
|
if (!found)
|
||||||
|
goto nothing;
|
||||||
|
|
||||||
|
r = pe_read_section_data(fd, found, PE_SECTION_SIZE_MAX, (void**) &cmdline_text, /* ret_size= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to load contents of section '.cmdline': %m");
|
||||||
|
|
||||||
|
if (trim_cmdline(&cmdline_text) < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
*ret_cmdline = TAKE_PTR(cmdline_text);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
nothing:
|
||||||
|
*ret_cmdline = NULL;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int insert_boot_entry_addon(
|
static int insert_boot_entry_addon(
|
||||||
|
@ -959,7 +1108,7 @@ static int boot_entries_find_unified_addons(
|
||||||
if (!j)
|
if (!j)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (find_addon_sections(fd, j, &cmdline) < 0)
|
if (pe_find_addon_sections(fd, j, &cmdline) <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
location = strdup(j);
|
location = strdup(j);
|
||||||
|
@ -1032,19 +1181,13 @@ static int boot_entries_find_unified(
|
||||||
return log_error_errno(r, "Failed to open '%s/%s': %m", root, dir);
|
return log_error_errno(r, "Failed to open '%s/%s': %m", root, dir);
|
||||||
|
|
||||||
FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read %s: %m", full)) {
|
FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read %s: %m", full)) {
|
||||||
_cleanup_free_ char *j = NULL, *osrelease = NULL, *cmdline = NULL;
|
|
||||||
_cleanup_close_ int fd = -EBADF;
|
|
||||||
|
|
||||||
if (!dirent_is_file(de))
|
if (!dirent_is_file(de))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!endswith_no_case(de->d_name, ".efi"))
|
if (!endswith_no_case(de->d_name, ".efi"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!GREEDY_REALLOC0(config->entries, config->n_entries + 1))
|
_cleanup_close_ int fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOFOLLOW|O_NOCTTY);
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOFOLLOW|O_NOCTTY);
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
log_warning_errno(errno, "Failed to open %s/%s, ignoring: %m", full, de->d_name);
|
log_warning_errno(errno, "Failed to open %s/%s, ignoring: %m", full, de->d_name);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1056,23 +1199,30 @@ static int boot_entries_find_unified(
|
||||||
if (r == 0) /* inode already seen or otherwise not relevant */
|
if (r == 0) /* inode already seen or otherwise not relevant */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
j = path_join(full, de->d_name);
|
_cleanup_free_ char *j = path_join(full, de->d_name);
|
||||||
if (!j)
|
if (!j)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (find_uki_sections(fd, j, &osrelease, &cmdline) < 0)
|
for (unsigned p = 0; p < UNIFIED_PROFILES_MAX; p++) {
|
||||||
continue;
|
_cleanup_free_ char *osrelease = NULL, *profile = NULL, *cmdline = NULL;
|
||||||
|
|
||||||
r = boot_entry_load_unified(root, j, osrelease, cmdline, config->entries + config->n_entries);
|
r = pe_find_uki_sections(fd, j, p, &osrelease, &profile, &cmdline);
|
||||||
if (r < 0)
|
if (r == 0) /* this profile does not exist, we are done */
|
||||||
continue;
|
break;
|
||||||
|
if (r < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* look for .efi.extra.d */
|
if (!GREEDY_REALLOC0(config->entries, config->n_entries + 2))
|
||||||
r = boot_entries_find_unified_local_addons(config, dirfd(d), de->d_name, full, config->entries + config->n_entries);
|
return log_oom();
|
||||||
if (r < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
config->n_entries++;
|
if (boot_entry_load_unified(root, j, p, osrelease, profile, cmdline, config->entries + config->n_entries) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
config->n_entries++;
|
||||||
|
|
||||||
|
/* look for .efi.extra.d */
|
||||||
|
(void) boot_entries_find_unified_local_addons(config, dirfd(d), de->d_name, full, config->entries + config->n_entries);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1648,8 +1798,14 @@ int show_boot_entry(
|
||||||
|
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
|
||||||
if (e->id)
|
if (e->id) {
|
||||||
printf(" id: %s\n", e->id);
|
printf(" id: %s", e->id);
|
||||||
|
|
||||||
|
if (e->id_without_profile && !streq_ptr(e->id, e->id_without_profile))
|
||||||
|
printf(" (without profile: %s)\n", e->id_without_profile);
|
||||||
|
else
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
if (e->path) {
|
if (e->path) {
|
||||||
_cleanup_free_ char *text = NULL, *link = NULL;
|
_cleanup_free_ char *text = NULL, *link = NULL;
|
||||||
|
|
||||||
|
@ -1673,7 +1829,7 @@ int show_boot_entry(
|
||||||
if (e->tries_done != UINT_MAX)
|
if (e->tries_done != UINT_MAX)
|
||||||
printf("; %u done\n", e->tries_done);
|
printf("; %u done\n", e->tries_done);
|
||||||
else
|
else
|
||||||
printf("\n");
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e->sort_key)
|
if (e->sort_key)
|
||||||
|
|
|
@ -38,6 +38,7 @@ typedef struct BootEntry {
|
||||||
bool reported_by_loader;
|
bool reported_by_loader;
|
||||||
char *id; /* This is the file basename (including extension!) */
|
char *id; /* This is the file basename (including extension!) */
|
||||||
char *id_old; /* Old-style ID, for deduplication purposes. */
|
char *id_old; /* Old-style ID, for deduplication purposes. */
|
||||||
|
char *id_without_profile; /* id without profile suffixed */
|
||||||
char *path; /* This is the full path to the drop-in file */
|
char *path; /* This is the full path to the drop-in file */
|
||||||
char *root; /* The root path in which the drop-in was found, i.e. to which 'kernel', 'efi' and 'initrd' are relative */
|
char *root; /* The root path in which the drop-in was found, i.e. to which 'kernel', 'efi' and 'initrd' are relative */
|
||||||
char *title;
|
char *title;
|
||||||
|
@ -55,6 +56,7 @@ typedef struct BootEntry {
|
||||||
char **device_tree_overlay;
|
char **device_tree_overlay;
|
||||||
unsigned tries_left;
|
unsigned tries_left;
|
||||||
unsigned tries_done;
|
unsigned tries_done;
|
||||||
|
unsigned profile;
|
||||||
} BootEntry;
|
} BootEntry;
|
||||||
|
|
||||||
#define BOOT_ENTRY_INIT(t) \
|
#define BOOT_ENTRY_INIT(t) \
|
||||||
|
|
|
@ -395,9 +395,9 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_ret) {
|
int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **ret) {
|
||||||
_cleanup_free_ char *ret = NULL;
|
_cleanup_free_ char *result = NULL;
|
||||||
size_t n = 0;
|
size_t n_result = 0, n_unescaped = 0;
|
||||||
const char *p;
|
const char *p;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
int r;
|
int r;
|
||||||
|
@ -427,17 +427,18 @@ int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_r
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
n_unescaped += r + !first; /* Count unescaped length to make max length determination below */
|
||||||
|
|
||||||
if (_ret) {
|
if (ret) {
|
||||||
if (!GREEDY_REALLOC(ret, n + !first + DNS_LABEL_ESCAPED_MAX))
|
if (!GREEDY_REALLOC(result, n_result + !first + DNS_LABEL_ESCAPED_MAX))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
|
r = dns_label_escape(label, r, result + n_result + !first, DNS_LABEL_ESCAPED_MAX);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
ret[n] = '.';
|
result[n_result] = '.';
|
||||||
} else {
|
} else {
|
||||||
char escaped[DNS_LABEL_ESCAPED_MAX];
|
char escaped[DNS_LABEL_ESCAPED_MAX];
|
||||||
|
|
||||||
|
@ -446,28 +447,34 @@ int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_r
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
n += r + !first;
|
n_result += r + !first;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
if (n > DNS_HOSTNAME_MAX)
|
if (n_unescaped == 0) {
|
||||||
return -EINVAL;
|
/* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
|
||||||
|
|
||||||
if (_ret) {
|
if (ret) {
|
||||||
if (n == 0) {
|
if (!GREEDY_REALLOC(result, 2)) /* Room for dot, and already pre-allocate space for the trailing NUL byte at the same time */
|
||||||
/* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
|
|
||||||
if (!GREEDY_REALLOC(ret, 2))
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret[n++] = '.';
|
result[n_result++] = '.';
|
||||||
} else {
|
|
||||||
if (!GREEDY_REALLOC(ret, n + 1))
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret[n] = 0;
|
n_unescaped++;
|
||||||
*_ret = TAKE_PTR(ret);
|
}
|
||||||
|
|
||||||
|
if (n_unescaped > DNS_HOSTNAME_MAX) /* Enforce max length check on unescaped length */
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
/* Suffix with a NUL byte */
|
||||||
|
if (!GREEDY_REALLOC(result, n_result + 1))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
result[n_result] = 0;
|
||||||
|
*ret = TAKE_PTR(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 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",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ static int uki_read_pretty_name(
|
||||||
assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
|
assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
r = pe_read_section_data(
|
r = pe_read_section_data_by_name(
|
||||||
fd,
|
fd,
|
||||||
pe_header,
|
pe_header,
|
||||||
sections,
|
sections,
|
||||||
|
@ -91,13 +92,13 @@ static int inspect_uki(
|
||||||
assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
|
assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
|
||||||
|
|
||||||
if (ret_cmdline) {
|
if (ret_cmdline) {
|
||||||
r = pe_read_section_data(fd, pe_header, sections, ".cmdline", PE_SECTION_READ_MAX, (void**) &cmdline, NULL);
|
r = pe_read_section_data_by_name(fd, pe_header, sections, ".cmdline", PE_SECTION_READ_MAX, (void**) &cmdline, NULL);
|
||||||
if (r < 0 && r != -ENXIO) /* If the section doesn't exist, that's fine */
|
if (r < 0 && r != -ENXIO) /* If the section doesn't exist, that's fine */
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret_uname) {
|
if (ret_uname) {
|
||||||
r = pe_read_section_data(fd, pe_header, sections, ".uname", PE_SECTION_READ_MAX, (void**) &uname, NULL);
|
r = pe_read_section_data_by_name(fd, pe_header, sections, ".uname", PE_SECTION_READ_MAX, (void**) &uname, NULL);
|
||||||
if (r < 0 && r != -ENXIO) /* If the section doesn't exist, that's fine */
|
if (r < 0 && r != -ENXIO) /* If the section doesn't exist, that's fine */
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "pe-binary.h"
|
#include "pe-binary.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
#include "uki.h"
|
||||||
|
|
||||||
bool pe_header_is_64bit(const PeHeader *h) {
|
bool pe_header_is_64bit(const PeHeader *h) {
|
||||||
assert(h);
|
assert(h);
|
||||||
|
@ -37,22 +38,21 @@ const IMAGE_DATA_DIRECTORY *pe_header_get_data_directory(
|
||||||
return PE_HEADER_OPTIONAL_FIELD(h, DataDirectory) + i;
|
return PE_HEADER_OPTIONAL_FIELD(h, DataDirectory) + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IMAGE_SECTION_HEADER *pe_header_find_section(
|
const IMAGE_SECTION_HEADER *pe_section_table_find(
|
||||||
const PeHeader *pe_header,
|
|
||||||
const IMAGE_SECTION_HEADER *sections,
|
const IMAGE_SECTION_HEADER *sections,
|
||||||
|
size_t n_sections,
|
||||||
const char *name) {
|
const char *name) {
|
||||||
|
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
assert(pe_header);
|
|
||||||
assert(name);
|
assert(name);
|
||||||
assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
|
assert(sections || n_sections == 0);
|
||||||
|
|
||||||
n = strlen(name);
|
n = strlen(name);
|
||||||
if (n > sizeof(sections[0].Name)) /* Too long? */
|
if (n > sizeof(sections[0].Name)) /* Too long? */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
FOREACH_ARRAY(section, sections, le16toh(pe_header->pe.NumberOfSections))
|
FOREACH_ARRAY(section, sections, n_sections)
|
||||||
if (memcmp(section->Name, name, n) == 0 &&
|
if (memcmp(section->Name, name, n) == 0 &&
|
||||||
memeqzero(section->Name + n, sizeof(section->Name) - n))
|
memeqzero(section->Name + n, sizeof(section->Name) - n))
|
||||||
return section;
|
return section;
|
||||||
|
@ -60,6 +60,16 @@ const IMAGE_SECTION_HEADER *pe_header_find_section(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IMAGE_SECTION_HEADER* pe_header_find_section(
|
||||||
|
const PeHeader *pe_header,
|
||||||
|
const IMAGE_SECTION_HEADER *sections,
|
||||||
|
const char *name) {
|
||||||
|
|
||||||
|
assert(pe_header);
|
||||||
|
|
||||||
|
return pe_section_table_find(sections, le16toh(pe_header->pe.NumberOfSections), name);
|
||||||
|
}
|
||||||
|
|
||||||
int pe_load_headers(
|
int pe_load_headers(
|
||||||
int fd,
|
int fd,
|
||||||
IMAGE_DOS_HEADER **ret_dos_header,
|
IMAGE_DOS_HEADER **ret_dos_header,
|
||||||
|
@ -173,43 +183,28 @@ int pe_load_sections(
|
||||||
|
|
||||||
int pe_read_section_data(
|
int pe_read_section_data(
|
||||||
int fd,
|
int fd,
|
||||||
const PeHeader *pe_header,
|
const IMAGE_SECTION_HEADER *section,
|
||||||
const IMAGE_SECTION_HEADER *sections,
|
|
||||||
const char *name,
|
|
||||||
size_t max_size,
|
size_t max_size,
|
||||||
void **ret,
|
void **ret,
|
||||||
size_t *ret_size) {
|
size_t *ret_size) {
|
||||||
|
|
||||||
const IMAGE_SECTION_HEADER *section;
|
|
||||||
_cleanup_free_ void *data = NULL;
|
|
||||||
size_t n;
|
|
||||||
ssize_t ss;
|
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(pe_header);
|
assert(section);
|
||||||
assert(sections || pe_header->pe.NumberOfSections == 0);
|
|
||||||
assert(name);
|
|
||||||
|
|
||||||
section = pe_header_find_section(pe_header, sections, name);
|
size_t n = le32toh(section->VirtualSize);
|
||||||
if (!section)
|
|
||||||
return -ENXIO;
|
|
||||||
|
|
||||||
n = le32toh(section->VirtualSize);
|
|
||||||
if (n > MIN(max_size, (size_t) SSIZE_MAX))
|
if (n > MIN(max_size, (size_t) SSIZE_MAX))
|
||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
|
|
||||||
data = malloc(n+1);
|
_cleanup_free_ void *data = malloc(n+1);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ss = pread(fd, data, n, le32toh(section->PointerToRawData));
|
ssize_t ss = pread(fd, data, n, le32toh(section->PointerToRawData));
|
||||||
if (ss < 0)
|
if (ss < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
if ((size_t) ss != n)
|
if ((size_t) ss != n)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
((uint8_t*) data)[n] = 0; /* NUL terminate, no matter what */
|
|
||||||
|
|
||||||
if (ret_size)
|
if (ret_size)
|
||||||
*ret_size = n;
|
*ret_size = n;
|
||||||
else {
|
else {
|
||||||
|
@ -221,12 +216,37 @@ int pe_read_section_data(
|
||||||
if (nul && !memeqzero(nul, n - (nul - (const char*) data))) /* If there's a NUL it must only be NULs from there on */
|
if (nul && !memeqzero(nul, n - (nul - (const char*) data))) /* If there's a NUL it must only be NULs from there on */
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
((uint8_t*) data)[n] = 0; /* NUL terminate, no matter what */
|
||||||
*ret = TAKE_PTR(data);
|
*ret = TAKE_PTR(data);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pe_read_section_data_by_name(
|
||||||
|
int fd,
|
||||||
|
const PeHeader *pe_header,
|
||||||
|
const IMAGE_SECTION_HEADER *sections,
|
||||||
|
const char *name,
|
||||||
|
size_t max_size,
|
||||||
|
void **ret,
|
||||||
|
size_t *ret_size) {
|
||||||
|
|
||||||
|
const IMAGE_SECTION_HEADER *section;
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
assert(pe_header);
|
||||||
|
assert(sections || pe_header->pe.NumberOfSections == 0);
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
section = pe_header_find_section(pe_header, sections, name);
|
||||||
|
if (!section)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
return pe_read_section_data(fd, section, max_size, ret, ret_size);
|
||||||
|
}
|
||||||
|
|
||||||
bool pe_is_uki(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections) {
|
bool pe_is_uki(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections) {
|
||||||
assert(pe_header);
|
assert(pe_header);
|
||||||
assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
|
assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
|
||||||
|
@ -240,3 +260,27 @@ bool pe_is_uki(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections)
|
||||||
pe_header_find_section(pe_header, sections, ".osrel") &&
|
pe_header_find_section(pe_header, sections, ".osrel") &&
|
||||||
pe_header_find_section(pe_header, sections, ".linux");
|
pe_header_find_section(pe_header, sections, ".linux");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pe_is_addon(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections) {
|
||||||
|
assert(pe_header);
|
||||||
|
assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
|
||||||
|
|
||||||
|
if (le16toh(pe_header->optional.Subsystem) != IMAGE_SUBSYSTEM_EFI_APPLICATION)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Add-ons do not have a Linux kernel, but do have either .cmdline or .dtb (currently) */
|
||||||
|
return !pe_header_find_section(pe_header, sections, ".linux") &&
|
||||||
|
(pe_header_find_section(pe_header, sections, ".cmdline") ||
|
||||||
|
pe_header_find_section(pe_header, sections, ".dtb") ||
|
||||||
|
pe_header_find_section(pe_header, sections, ".ucode"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pe_is_native(const PeHeader *pe_header) {
|
||||||
|
assert(pe_header);
|
||||||
|
|
||||||
|
#ifdef _IMAGE_FILE_MACHINE_NATIVE
|
||||||
|
return le16toh(pe_header->pe.Machine) == _IMAGE_FILE_MACHINE_NATIVE;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -135,10 +135,15 @@ bool pe_header_is_64bit(const PeHeader *h);
|
||||||
|
|
||||||
const IMAGE_DATA_DIRECTORY *pe_header_get_data_directory(const PeHeader *h, size_t i);
|
const IMAGE_DATA_DIRECTORY *pe_header_get_data_directory(const PeHeader *h, size_t i);
|
||||||
const IMAGE_SECTION_HEADER *pe_header_find_section(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections, const char *name);
|
const IMAGE_SECTION_HEADER *pe_header_find_section(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections, const char *name);
|
||||||
|
const IMAGE_SECTION_HEADER *pe_section_table_find(const IMAGE_SECTION_HEADER *sections, size_t n_sections, const char *name);
|
||||||
|
|
||||||
int pe_load_headers(int fd, IMAGE_DOS_HEADER **ret_dos_header, PeHeader **ret_pe_header);
|
int pe_load_headers(int fd, IMAGE_DOS_HEADER **ret_dos_header, PeHeader **ret_pe_header);
|
||||||
|
|
||||||
int pe_load_sections(int fd, const IMAGE_DOS_HEADER *dos_header, const PeHeader *pe_header, IMAGE_SECTION_HEADER **ret_sections);
|
int pe_load_sections(int fd, const IMAGE_DOS_HEADER *dos_header, const PeHeader *pe_header, IMAGE_SECTION_HEADER **ret_sections);
|
||||||
int pe_read_section_data(int fd, const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections, const char *name, size_t max_size, void **ret, size_t *ret_size);
|
int pe_read_section_data(int fd, const IMAGE_SECTION_HEADER *section, size_t max_size, void **ret, size_t *ret_size);
|
||||||
|
int pe_read_section_data_by_name(int fd, const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections, const char *name, size_t max_size, void **ret, size_t *ret_size);
|
||||||
|
|
||||||
bool pe_is_uki(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections);
|
bool pe_is_uki(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections);
|
||||||
|
bool pe_is_addon(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections);
|
||||||
|
|
||||||
|
bool pe_is_native(const PeHeader *pe_header);
|
||||||
|
|
|
@ -942,7 +942,7 @@ int pty_forward_new(
|
||||||
|
|
||||||
(void) sd_event_source_set_description(f->master_event_source, "ptyfwd-master");
|
(void) sd_event_source_set_description(f->master_event_source, "ptyfwd-master");
|
||||||
|
|
||||||
r = sd_event_add_signal(f->event, &f->sigwinch_event_source, SIGWINCH, on_sigwinch_event, f);
|
r = sd_event_add_signal(f->event, &f->sigwinch_event_source, SIGWINCH|SD_EVENT_SIGNAL_PROCMASK, on_sigwinch_event, f);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -375,6 +375,9 @@ static void test_dns_name_is_valid_one(const char *s, int ret, int ret_ldh) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dns_name_is_valid) {
|
TEST(dns_name_is_valid) {
|
||||||
|
test_dns_name_is_valid_one("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[._qotd._tcp.local", 1, 0);
|
||||||
|
test_dns_name_is_valid_one("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]._qotd._tcp.local", 0, 0);
|
||||||
|
|
||||||
test_dns_name_is_valid_one("foo", 1, 1);
|
test_dns_name_is_valid_one("foo", 1, 1);
|
||||||
test_dns_name_is_valid_one("foo.", 1, 1);
|
test_dns_name_is_valid_one("foo.", 1, 1);
|
||||||
test_dns_name_is_valid_one("foo..", 0, 0);
|
test_dns_name_is_valid_one("foo..", 0, 0);
|
||||||
|
|
|
@ -1132,15 +1132,21 @@ int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
(void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
r = sd_event_set_signal_exit(m->event, true);
|
||||||
(void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
if (r < 0)
|
||||||
(void) sd_event_add_signal(m->event, NULL, SIGRTMIN+18, sigrtmin18_handler, NULL);
|
return r;
|
||||||
|
|
||||||
|
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to install SIGRTMIN+18 signal handler, ignoring: %m");
|
||||||
|
|
||||||
r = sd_event_add_memory_pressure(m->event, NULL, NULL, NULL);
|
r = sd_event_add_memory_pressure(m->event, NULL, NULL, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m");
|
log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m");
|
||||||
|
|
||||||
(void) sd_event_set_watchdog(m->event, true);
|
r = sd_event_set_watchdog(m->event, true);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to enable watchdog handling, ignoring: %m");
|
||||||
|
|
||||||
/* Load previous synchronization state */
|
/* Load previous synchronization state */
|
||||||
r = access("/run/systemd/timesync/synchronized", F_OK);
|
r = access("/run/systemd/timesync/synchronized", F_OK);
|
||||||
|
|
|
@ -179,8 +179,6 @@ static int run(int argc, char *argv[]) {
|
||||||
return log_error_errno(r, "Failed to drop privileges: %m");
|
return log_error_errno(r, "Failed to drop privileges: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
|
|
||||||
|
|
||||||
r = manager_new(&m);
|
r = manager_new(&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to allocate manager: %m");
|
return log_error_errno(r, "Failed to allocate manager: %m");
|
||||||
|
|
|
@ -184,19 +184,13 @@ static int run(int argc, char * argv[]) {
|
||||||
};
|
};
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
|
|
||||||
|
|
||||||
r = sd_event_default(&event);
|
r = sd_event_default(&event);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to allocate event loop: %m");
|
return log_error_errno(r, "Failed to allocate event loop: %m");
|
||||||
|
|
||||||
r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
r = sd_event_set_signal_exit(event, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to create sigterm event source: %m");
|
return log_error_errno(r, "Failed to enable SIGTERM/SIGINT handling: %m");
|
||||||
|
|
||||||
r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to create sigint event source: %m");
|
|
||||||
|
|
||||||
r = sd_event_set_watchdog(event, true);
|
r = sd_event_set_watchdog(event, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -153,8 +153,6 @@ Manager* manager_free(Manager *manager) {
|
||||||
|
|
||||||
sd_event_source_unref(manager->inotify_event);
|
sd_event_source_unref(manager->inotify_event);
|
||||||
sd_event_source_unref(manager->kill_workers_event);
|
sd_event_source_unref(manager->kill_workers_event);
|
||||||
sd_event_source_unref(manager->memory_pressure_event_source);
|
|
||||||
sd_event_source_unref(manager->sigrtmin18_event_source);
|
|
||||||
sd_event_unref(manager->event);
|
sd_event_unref(manager->event);
|
||||||
|
|
||||||
free(manager->cgroup);
|
free(manager->cgroup);
|
||||||
|
@ -1352,13 +1350,13 @@ int manager_main(Manager *manager) {
|
||||||
return log_error_errno(r, "Failed to create post event source: %m");
|
return log_error_errno(r, "Failed to create post event source: %m");
|
||||||
|
|
||||||
/* Eventually, we probably want to do more here on memory pressure, for example, kill idle workers immediately */
|
/* Eventually, we probably want to do more here on memory pressure, for example, kill idle workers immediately */
|
||||||
r = sd_event_add_memory_pressure(manager->event, &manager->memory_pressure_event_source, NULL, NULL);
|
r = sd_event_add_memory_pressure(manager->event, /* ret_event_source= */ NULL, /* callback= */ NULL, /* userdata= */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) || ERRNO_IS_PRIVILEGE(r) || (r == -EHOSTDOWN) ? LOG_DEBUG : LOG_WARNING, r,
|
log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) || ERRNO_IS_PRIVILEGE(r) || (r == -EHOSTDOWN) ? LOG_DEBUG : LOG_WARNING, r,
|
||||||
"Failed to allocate memory pressure watch, ignoring: %m");
|
"Failed to allocate memory pressure watch, ignoring: %m");
|
||||||
|
|
||||||
r = sd_event_add_signal(manager->event, &manager->memory_pressure_event_source,
|
r = sd_event_add_signal(manager->event, /* ret_event_source= */ NULL,
|
||||||
(SIGRTMIN+18) | SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, NULL);
|
(SIGRTMIN+18) | SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata= */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to allocate SIGRTMIN+18 event source, ignoring: %m");
|
return log_error_errno(r, "Failed to allocate SIGRTMIN+18 event source, ignoring: %m");
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,6 @@ typedef struct Manager {
|
||||||
|
|
||||||
sd_event_source *kill_workers_event;
|
sd_event_source *kill_workers_event;
|
||||||
|
|
||||||
sd_event_source *memory_pressure_event_source;
|
|
||||||
sd_event_source *sigrtmin18_event_source;
|
|
||||||
|
|
||||||
usec_t last_usec;
|
usec_t last_usec;
|
||||||
|
|
||||||
ResolveNameTiming resolve_name_timing;
|
ResolveNameTiming resolve_name_timing;
|
||||||
|
|
|
@ -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_INVALID = -EINVAL,
|
|
||||||
|
_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,
|
||||||
} 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,13 +1740,17 @@ 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:
|
||||||
match = STR_IN_SET(str, "subsystem", "class", "bus");
|
if (case_insensitive)
|
||||||
|
match = STRCASE_IN_SET(str, "subsystem", "class", "bus");
|
||||||
|
else
|
||||||
|
match = STR_IN_SET(str, "subsystem", "class", "bus");
|
||||||
break;
|
break;
|
||||||
case MATCH_TYPE_PLAIN_WITH_EMPTY:
|
case MATCH_TYPE_PLAIN_WITH_EMPTY:
|
||||||
if (isempty(str)) {
|
if (isempty(str)) {
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -208,9 +208,11 @@ int monitor_main(int argc, char *argv[], void *userdata) {
|
||||||
goto finalize;
|
goto finalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
|
r = sd_event_set_signal_exit(event, true);
|
||||||
(void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
if (r < 0) {
|
||||||
(void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
|
log_error_errno(r, "Failed to install SIGINT/SIGTERM handling: %m");
|
||||||
|
goto finalize;
|
||||||
|
}
|
||||||
|
|
||||||
printf("monitor will print the received events for:\n");
|
printf("monitor will print the received events for:\n");
|
||||||
if (arg_print_udev) {
|
if (arg_print_udev) {
|
||||||
|
|
|
@ -2124,7 +2124,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, /* old_sigset=*/ NULL, SIGCHLD, SIGWINCH) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask=*/ NULL, SIGCHLD) >= 0);
|
||||||
|
|
||||||
_cleanup_(sd_event_source_unrefp) sd_event_source *notify_event_source = NULL;
|
_cleanup_(sd_event_source_unrefp) sd_event_source *notify_event_source = NULL;
|
||||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
|
||||||
|
# ex: ts=8 sw=4 sts=4 et filetype=sh
|
||||||
|
# shellcheck disable=SC2233,SC2235
|
||||||
|
set -eux
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# shellcheck source=test/units/util.sh
|
||||||
|
. "$(dirname "$0")"/util.sh
|
||||||
|
|
||||||
|
# Arrays cannot be exported, so redefine in each test script
|
||||||
|
ARGS=()
|
||||||
|
if [[ -v ASAN_OPTIONS || -v UBSAN_OPTIONS ]]; then
|
||||||
|
# If we're running under sanitizers, we need to use a less restrictive
|
||||||
|
# profile, otherwise LSan syscall would get blocked by seccomp
|
||||||
|
ARGS+=(--profile=trusted)
|
||||||
|
fi
|
||||||
|
|
||||||
|
unsquashfs -dest /tmp/minimal_0 /usr/share/minimal_0.raw
|
||||||
|
unsquashfs -dest /tmp/minimal_1 /usr/share/minimal_1.raw
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/minimal_0 minimal-app0
|
||||||
|
|
||||||
|
systemctl is-active minimal-app0.service
|
||||||
|
systemctl is-active minimal-app0-foo.service
|
||||||
|
systemctl is-active minimal-app0-bar.service && exit 1
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" reattach --now --enable --runtime /tmp/minimal_1 minimal-app0
|
||||||
|
|
||||||
|
systemctl is-active minimal-app0.service
|
||||||
|
systemctl is-active minimal-app0-bar.service
|
||||||
|
systemctl is-active minimal-app0-foo.service && exit 1
|
||||||
|
|
||||||
|
portablectl list | grep -q -F "minimal_1"
|
||||||
|
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1'
|
||||||
|
|
||||||
|
portablectl detach --now --enable --runtime /tmp/minimal_1 minimal-app0
|
||||||
|
|
||||||
|
portablectl list | grep -q -F "No images."
|
||||||
|
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' && exit 1
|
||||||
|
|
||||||
|
mkdir /tmp/rootdir /tmp/app0 /tmp/app1 /tmp/overlay /tmp/os-release-fix /tmp/os-release-fix/etc
|
||||||
|
mount /tmp/app0.raw /tmp/app0
|
||||||
|
mount /tmp/app1.raw /tmp/app1
|
||||||
|
mount /usr/share/minimal_0.raw /tmp/rootdir
|
||||||
|
|
||||||
|
# Fix up os-release to drop the valid PORTABLE_SERVICES field (because we are
|
||||||
|
# bypassing the sysext logic in portabled here it will otherwise not see the
|
||||||
|
# extensions additional valid prefix)
|
||||||
|
grep -v "^PORTABLE_PREFIXES=" /tmp/rootdir/etc/os-release >/tmp/os-release-fix/etc/os-release
|
||||||
|
|
||||||
|
mount -t overlay overlay -o lowerdir=/tmp/os-release-fix:/tmp/app1:/tmp/rootdir /tmp/overlay
|
||||||
|
|
||||||
|
grep . /tmp/overlay/usr/lib/extension-release.d/*
|
||||||
|
grep . /tmp/overlay/etc/os-release
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/overlay app1
|
||||||
|
|
||||||
|
systemctl is-active app1.service
|
||||||
|
|
||||||
|
portablectl detach --now --runtime overlay app1
|
||||||
|
|
||||||
|
# Ensure --force works also when symlinking
|
||||||
|
mkdir -p /run/systemd/system.attached/app1.service.d
|
||||||
|
cat <<EOF >/run/systemd/system.attached/app1.service
|
||||||
|
[Unit]
|
||||||
|
Description=App 1
|
||||||
|
EOF
|
||||||
|
cat <<EOF >/run/systemd/system.attached/app1.service.d/10-profile.conf
|
||||||
|
[Unit]
|
||||||
|
Description=App 1
|
||||||
|
EOF
|
||||||
|
cat <<EOF >/run/systemd/system.attached/app1.service.d/20-portable.conf
|
||||||
|
[Unit]
|
||||||
|
Description=App 1
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" attach --force --copy=symlink --now --runtime /tmp/overlay app1
|
||||||
|
|
||||||
|
systemctl is-active app1.service
|
||||||
|
|
||||||
|
portablectl detach --now --runtime overlay app1
|
||||||
|
|
||||||
|
umount /tmp/overlay
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1
|
||||||
|
|
||||||
|
systemctl is-active app0.service
|
||||||
|
systemctl is-active app1.service
|
||||||
|
|
||||||
|
portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/rootdir/usr/lib/os-release
|
||||||
|
portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app0/usr/lib/extension-release.d/extension-release.app0
|
||||||
|
portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app1/usr/lib/extension-release.d/extension-release.app2
|
||||||
|
portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app1/usr/lib/systemd/system/app1.service
|
||||||
|
portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app0/usr/lib/systemd/system/app0.service
|
||||||
|
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE=app0" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_ROOT=rootdir" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app1" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app_1" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE=app1" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_ROOT=rootdir" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app1" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app_1" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
||||||
|
|
||||||
|
portablectl detach --clean --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1
|
||||||
|
|
||||||
|
# Ensure --clean remove state and other directories belonging to the portable image being detached
|
||||||
|
test ! -d /var/lib/app0
|
||||||
|
test ! -d /run/app0
|
||||||
|
|
||||||
|
# Ensure that mixed mode copies the images and units (client-owned) but symlinks the profile (OS owned)
|
||||||
|
portablectl "${ARGS[@]}" attach --copy=mixed --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1
|
||||||
|
test -d /run/portables/app0
|
||||||
|
test -d /run/portables/app1
|
||||||
|
test -d /run/portables/rootdir
|
||||||
|
test -f /run/systemd/system.attached/app0.service
|
||||||
|
test -f /run/systemd/system.attached/app1.service
|
||||||
|
test -L /run/systemd/system.attached/app0.service.d/10-profile.conf
|
||||||
|
test -L /run/systemd/system.attached/app1.service.d/10-profile.conf
|
||||||
|
portablectl detach --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1
|
||||||
|
|
||||||
|
# Attempt to disable the app unit during detaching. Requires --copy=symlink to reproduce.
|
||||||
|
# Provides coverage for https://github.com/systemd/systemd/issues/23481
|
||||||
|
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/rootdir minimal-app0
|
||||||
|
portablectl detach --now --runtime --enable /tmp/rootdir minimal-app0
|
||||||
|
# attach and detach again to check if all drop-in configs are removed even if the main unit files are removed
|
||||||
|
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/rootdir minimal-app0
|
||||||
|
portablectl detach --now --runtime --enable /tmp/rootdir minimal-app0
|
||||||
|
|
||||||
|
# The wrong file should be ignored, given the right one has the xattr set
|
||||||
|
trap 'rm -rf /var/cache/wrongext' EXIT
|
||||||
|
mkdir -p /var/cache/wrongext/usr/lib/extension-release.d /var/cache/wrongext/usr/lib/systemd/system/
|
||||||
|
echo "[Service]" > /var/cache/wrongext/usr/lib/systemd/system/app0.service
|
||||||
|
touch /var/cache/wrongext/usr/lib/extension-release.d/extension-release.wrongext_somethingwrong.txt
|
||||||
|
cp /tmp/rootdir/usr/lib/os-release /var/cache/wrongext/usr/lib/extension-release.d/extension-release.app0
|
||||||
|
setfattr -n user.extension-release.strict -v "false" /var/cache/wrongext/usr/lib/extension-release.d/extension-release.app0
|
||||||
|
portablectl "${ARGS[@]}" attach --runtime --extension /var/cache/wrongext /tmp/rootdir app0
|
||||||
|
status="$(portablectl is-attached --extension wrongext rootdir)"
|
||||||
|
[[ "${status}" == "attached-runtime" ]]
|
||||||
|
portablectl detach --runtime --extension /var/cache/wrongext /tmp/rootdir app0
|
||||||
|
|
||||||
|
umount /tmp/rootdir
|
||||||
|
umount /tmp/app0
|
||||||
|
umount /tmp/app1
|
|
@ -0,0 +1,240 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
|
||||||
|
# ex: ts=8 sw=4 sts=4 et filetype=sh
|
||||||
|
# shellcheck disable=SC2233,SC2235
|
||||||
|
set -eux
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# shellcheck source=test/units/util.sh
|
||||||
|
. "$(dirname "$0")"/util.sh
|
||||||
|
|
||||||
|
# Arrays cannot be exported, so redefine in each test script
|
||||||
|
ARGS=()
|
||||||
|
if [[ -v ASAN_OPTIONS || -v UBSAN_OPTIONS ]]; then
|
||||||
|
# If we're running under sanitizers, we need to use a less restrictive
|
||||||
|
# profile, otherwise LSan syscall would get blocked by seccomp
|
||||||
|
ARGS+=(--profile=trusted)
|
||||||
|
fi
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" attach --now --runtime /usr/share/minimal_0.raw minimal-app0
|
||||||
|
|
||||||
|
portablectl is-attached minimal-app0
|
||||||
|
portablectl inspect /usr/share/minimal_0.raw minimal-app0.service
|
||||||
|
systemctl is-active minimal-app0.service
|
||||||
|
systemctl is-active minimal-app0-foo.service
|
||||||
|
systemctl is-active minimal-app0-bar.service && exit 1
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" reattach --now --runtime /usr/share/minimal_1.raw minimal-app0
|
||||||
|
|
||||||
|
portablectl is-attached minimal-app0
|
||||||
|
portablectl inspect /usr/share/minimal_0.raw minimal-app0.service
|
||||||
|
systemctl is-active minimal-app0.service
|
||||||
|
systemctl is-active minimal-app0-bar.service
|
||||||
|
systemctl is-active minimal-app0-foo.service && exit 1
|
||||||
|
|
||||||
|
portablectl list | grep -q -F "minimal_1"
|
||||||
|
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1'
|
||||||
|
|
||||||
|
portablectl detach --now --runtime /usr/share/minimal_1.raw minimal-app0
|
||||||
|
|
||||||
|
portablectl list | grep -q -F "No images."
|
||||||
|
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' && exit 1
|
||||||
|
|
||||||
|
# Ensure we don't regress (again) when using --force
|
||||||
|
|
||||||
|
mkdir -p /run/systemd/system.attached/minimal-app0.service.d/
|
||||||
|
cat <<EOF >/run/systemd/system.attached/minimal-app0.service
|
||||||
|
[Unit]
|
||||||
|
Description=Minimal App 0
|
||||||
|
EOF
|
||||||
|
cat <<EOF >/run/systemd/system.attached/minimal-app0.service.d/10-profile.conf
|
||||||
|
[Unit]
|
||||||
|
Description=Minimal App 0
|
||||||
|
EOF
|
||||||
|
cat <<EOF >/run/systemd/system.attached/minimal-app0.service.d/20-portable.conf
|
||||||
|
[Unit]
|
||||||
|
Description=Minimal App 0
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" attach --force --now --runtime /usr/share/minimal_0.raw minimal-app0
|
||||||
|
|
||||||
|
portablectl is-attached --force minimal-app0
|
||||||
|
portablectl inspect --force /usr/share/minimal_0.raw minimal-app0.service
|
||||||
|
systemctl is-active minimal-app0.service
|
||||||
|
systemctl is-active minimal-app0-foo.service
|
||||||
|
systemctl is-active minimal-app0-bar.service && exit 1
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" reattach --force --now --runtime /usr/share/minimal_1.raw minimal-app0
|
||||||
|
|
||||||
|
portablectl is-attached --force minimal-app0
|
||||||
|
portablectl inspect --force /usr/share/minimal_0.raw minimal-app0.service
|
||||||
|
systemctl is-active minimal-app0.service
|
||||||
|
systemctl is-active minimal-app0-bar.service
|
||||||
|
systemctl is-active minimal-app0-foo.service && exit 1
|
||||||
|
|
||||||
|
portablectl list | grep -q -F "minimal_1"
|
||||||
|
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1'
|
||||||
|
|
||||||
|
portablectl detach --force --now --runtime /usr/share/minimal_1.raw minimal-app0
|
||||||
|
|
||||||
|
portablectl list | grep -q -F "No images."
|
||||||
|
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' && exit 1
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0
|
||||||
|
|
||||||
|
systemctl is-active app0.service
|
||||||
|
status="$(portablectl is-attached --extension app0 minimal_0)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_ROOT=minimal_0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_1.raw app0
|
||||||
|
|
||||||
|
systemctl is-active app0.service
|
||||||
|
status="$(portablectl is-attached --extension app0 minimal_1)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_ROOT=minimal_1.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
|
|
||||||
|
portablectl detach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_1.raw app0
|
||||||
|
|
||||||
|
# Ensure versioned images are accepted without needing to use --force to override the extension-release
|
||||||
|
# matching
|
||||||
|
|
||||||
|
cp /tmp/app0.raw /tmp/app0_1.0.raw
|
||||||
|
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app0_1.0.raw /usr/share/minimal_0.raw app0
|
||||||
|
|
||||||
|
systemctl is-active app0.service
|
||||||
|
status="$(portablectl is-attached --extension app0_1 minimal_0)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
portablectl detach --now --runtime --extension /tmp/app0_1.0.raw /usr/share/minimal_1.raw app0
|
||||||
|
rm -f /tmp/app0_1.0.raw
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1
|
||||||
|
|
||||||
|
systemctl is-active app1.service
|
||||||
|
status="$(portablectl is-attached --extension app1 minimal_0)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
# Ensure that adding or removing a version to the image doesn't break reattaching
|
||||||
|
cp /tmp/app1.raw /tmp/app1_2.raw
|
||||||
|
portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1_2.raw /usr/share/minimal_1.raw app1
|
||||||
|
|
||||||
|
systemctl is-active app1.service
|
||||||
|
status="$(portablectl is-attached --extension app1_2 minimal_1)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1.raw /usr/share/minimal_1.raw app1
|
||||||
|
|
||||||
|
systemctl is-active app1.service
|
||||||
|
status="$(portablectl is-attached --extension app1 minimal_1)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
portablectl detach --force --no-reload --runtime --extension /tmp/app1.raw /usr/share/minimal_1.raw app1
|
||||||
|
portablectl "${ARGS[@]}" attach --force --no-reload --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl restart app1.service
|
||||||
|
|
||||||
|
systemctl is-active app1.service
|
||||||
|
status="$(portablectl is-attached --extension app1 minimal_0)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
portablectl detach --now --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1
|
||||||
|
|
||||||
|
# Ensure vpick works, including reattaching to a new image
|
||||||
|
mkdir -p /tmp/app1.v/
|
||||||
|
cp /tmp/app1.raw /tmp/app1.v/app1_1.0.raw
|
||||||
|
cp /tmp/app1_2.raw /tmp/app1.v/app1_2.0.raw
|
||||||
|
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_1.raw app1
|
||||||
|
|
||||||
|
systemctl is-active app1.service
|
||||||
|
status="$(portablectl is-attached --extension app1_2.0.raw minimal_1)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
rm -f /tmp/app1.v/app1_2.0.raw
|
||||||
|
portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_1.raw app1
|
||||||
|
|
||||||
|
systemctl is-active app1.service
|
||||||
|
status="$(portablectl is-attached --extension app1_1.0.raw minimal_1)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
portablectl detach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_0.raw app1
|
||||||
|
rm -f /tmp/app1.v/app1_1.0.raw
|
||||||
|
|
||||||
|
# Ensure that the combination of read-only images, state directory and dynamic user works, and that
|
||||||
|
# state is retained. Check after detaching, as on slow systems (eg: sanitizers) it might take a while
|
||||||
|
# after the service is attached before the file appears.
|
||||||
|
grep -q -F bar "${STATE_DIRECTORY}/app0/foo"
|
||||||
|
grep -q -F baz "${STATE_DIRECTORY}/app1/foo"
|
||||||
|
|
||||||
|
# Ensure that we can override the check on extension-release.NAME
|
||||||
|
cp /tmp/app0.raw /tmp/app10.raw
|
||||||
|
portablectl "${ARGS[@]}" attach --force --now --runtime --extension /tmp/app10.raw /usr/share/minimal_0.raw app0
|
||||||
|
|
||||||
|
systemctl is-active app0.service
|
||||||
|
status="$(portablectl is-attached --extension /tmp/app10.raw /usr/share/minimal_0.raw)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
portablectl inspect --force --cat --extension /tmp/app10.raw /usr/share/minimal_0.raw app0 | grep -q -F "Extension Release: /tmp/app10.raw"
|
||||||
|
|
||||||
|
# Ensure that we can detach even when an image has been deleted already (stop the unit manually as
|
||||||
|
# portablectl won't find it)
|
||||||
|
rm -f /tmp/app10.raw
|
||||||
|
systemctl stop app0.service
|
||||||
|
portablectl detach --force --runtime --extension /tmp/app10.raw /usr/share/minimal_0.raw app0
|
||||||
|
|
||||||
|
# portablectl also accepts confexts
|
||||||
|
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw app0
|
||||||
|
|
||||||
|
systemctl is-active app0.service
|
||||||
|
status="$(portablectl is-attached --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw)"
|
||||||
|
[[ "${status}" == "running-runtime" ]]
|
||||||
|
|
||||||
|
portablectl inspect --force --cat --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw app0 | grep -q -F "Extension Release: /tmp/conf0.raw"
|
||||||
|
|
||||||
|
portablectl detach --now --runtime --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw app0
|
||||||
|
|
||||||
|
# Ensure that mixed mode copies the images and units (client-owned) but symlinks the profile (OS owned)
|
||||||
|
portablectl "${ARGS[@]}" attach --copy=mixed --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0
|
||||||
|
test -f /run/portables/app0.raw
|
||||||
|
test -f /run/portables/minimal_0.raw
|
||||||
|
test -f /run/systemd/system.attached/app0.service
|
||||||
|
test -L /run/systemd/system.attached/app0.service.d/10-profile.conf
|
||||||
|
portablectl detach --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0
|
||||||
|
|
||||||
|
# Ensure that when two portables share the same base image, removing one doesn't remove the other too
|
||||||
|
|
||||||
|
portablectl "${ARGS[@]}" attach --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0
|
||||||
|
portablectl "${ARGS[@]}" attach --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1
|
||||||
|
|
||||||
|
status="$(portablectl is-attached --extension app0 minimal_0)"
|
||||||
|
[[ "${status}" == "attached-runtime" ]]
|
||||||
|
status="$(portablectl is-attached --extension app1 minimal_0)"
|
||||||
|
[[ "${status}" == "attached-runtime" ]]
|
||||||
|
|
||||||
|
(! portablectl detach --runtime /usr/share/minimal_0.raw app)
|
||||||
|
|
||||||
|
status="$(portablectl is-attached --extension app0 minimal_0)"
|
||||||
|
[[ "${status}" == "attached-runtime" ]]
|
||||||
|
status="$(portablectl is-attached --extension app1 minimal_0)"
|
||||||
|
[[ "${status}" == "attached-runtime" ]]
|
||||||
|
|
||||||
|
# Ensure 'portablectl list' shows the correct status for both images
|
||||||
|
portablectl list
|
||||||
|
portablectl list | grep -F "minimal_0" | grep -q -F "attached-runtime"
|
||||||
|
portablectl list | grep -F "app0" | grep -q -F "attached-runtime"
|
||||||
|
portablectl list | grep -F "app1" | grep -q -F "attached-runtime"
|
||||||
|
|
||||||
|
portablectl detach --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app
|
||||||
|
|
||||||
|
status="$(portablectl is-attached --extension app1 minimal_0)"
|
||||||
|
[[ "${status}" == "attached-runtime" ]]
|
||||||
|
|
||||||
|
portablectl detach --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app
|
|
@ -5,6 +5,9 @@
|
||||||
set -eux
|
set -eux
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
|
# shellcheck source=test/units/test-control.sh
|
||||||
|
. "$(dirname "$0")"/test-control.sh
|
||||||
|
|
||||||
# shellcheck source=test/units/util.sh
|
# shellcheck source=test/units/util.sh
|
||||||
. "$(dirname "$0")"/util.sh
|
. "$(dirname "$0")"/util.sh
|
||||||
|
|
||||||
|
@ -18,9 +21,14 @@ DefaultEnvironment=SYSTEMD_DISSECT_VERITY_TIMEOUT_SEC=30
|
||||||
ManagerEnvironment=SYSTEMD_DISSECT_VERITY_TIMEOUT_SEC=30
|
ManagerEnvironment=SYSTEMD_DISSECT_VERITY_TIMEOUT_SEC=30
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
mkdir -p /run/systemd/system/systemd-portabled.service.d/
|
||||||
|
cat <<EOF >/run/systemd/system/systemd-portabled.service.d/override.conf
|
||||||
|
[Service]
|
||||||
|
Environment=SYSTEMD_LOG_LEVEL=debug
|
||||||
|
EOF
|
||||||
|
|
||||||
systemctl daemon-reexec
|
systemctl daemon-reexec
|
||||||
|
|
||||||
export SYSTEMD_DISSECT_VERITY_TIMEOUT_SEC=30
|
|
||||||
|
|
||||||
udevadm control --log-level debug
|
udevadm control --log-level debug
|
||||||
|
|
||||||
|
@ -33,6 +41,11 @@ if [[ -v ASAN_OPTIONS || -v UBSAN_OPTIONS ]]; then
|
||||||
# With the trusted profile DynamicUser is disabled, so the storage is not in private/
|
# With the trusted profile DynamicUser is disabled, so the storage is not in private/
|
||||||
STATE_DIRECTORY=/var/lib/
|
STATE_DIRECTORY=/var/lib/
|
||||||
fi
|
fi
|
||||||
|
export STATE_DIRECTORY
|
||||||
|
export SYSTEMD_LOG_LEVEL=debug
|
||||||
|
export SYSTEMD_DISSECT_VERITY_TIMEOUT_SEC=30
|
||||||
|
|
||||||
|
# Quick smoke tests
|
||||||
|
|
||||||
systemd-dissect --no-pager /usr/share/minimal_0.raw | grep -q '✓ portable service'
|
systemd-dissect --no-pager /usr/share/minimal_0.raw | grep -q '✓ portable service'
|
||||||
systemd-dissect --no-pager /usr/share/minimal_1.raw | grep -q '✓ portable service'
|
systemd-dissect --no-pager /usr/share/minimal_1.raw | grep -q '✓ portable service'
|
||||||
|
@ -40,373 +53,6 @@ systemd-dissect --no-pager /tmp/app0.raw | grep -q '✓ sysext for portable serv
|
||||||
systemd-dissect --no-pager /tmp/app1.raw | grep -q '✓ sysext for portable service'
|
systemd-dissect --no-pager /tmp/app1.raw | grep -q '✓ sysext for portable service'
|
||||||
systemd-dissect --no-pager /tmp/conf0.raw | grep -q '✓ confext for portable service'
|
systemd-dissect --no-pager /tmp/conf0.raw | grep -q '✓ confext for portable service'
|
||||||
|
|
||||||
export SYSTEMD_LOG_LEVEL=debug
|
|
||||||
mkdir -p /run/systemd/system/systemd-portabled.service.d/
|
|
||||||
cat <<EOF >/run/systemd/system/systemd-portabled.service.d/override.conf
|
|
||||||
[Service]
|
|
||||||
Environment=SYSTEMD_LOG_LEVEL=debug
|
|
||||||
EOF
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" attach --now --runtime /usr/share/minimal_0.raw minimal-app0
|
|
||||||
|
|
||||||
portablectl is-attached minimal-app0
|
|
||||||
portablectl inspect /usr/share/minimal_0.raw minimal-app0.service
|
|
||||||
systemctl is-active minimal-app0.service
|
|
||||||
systemctl is-active minimal-app0-foo.service
|
|
||||||
systemctl is-active minimal-app0-bar.service && exit 1
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" reattach --now --runtime /usr/share/minimal_1.raw minimal-app0
|
|
||||||
|
|
||||||
portablectl is-attached minimal-app0
|
|
||||||
portablectl inspect /usr/share/minimal_0.raw minimal-app0.service
|
|
||||||
systemctl is-active minimal-app0.service
|
|
||||||
systemctl is-active minimal-app0-bar.service
|
|
||||||
systemctl is-active minimal-app0-foo.service && exit 1
|
|
||||||
|
|
||||||
portablectl list | grep -q -F "minimal_1"
|
|
||||||
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1'
|
|
||||||
|
|
||||||
portablectl detach --now --runtime /usr/share/minimal_1.raw minimal-app0
|
|
||||||
|
|
||||||
portablectl list | grep -q -F "No images."
|
|
||||||
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' && exit 1
|
|
||||||
|
|
||||||
# Ensure we don't regress (again) when using --force
|
|
||||||
|
|
||||||
mkdir -p /run/systemd/system.attached/minimal-app0.service.d/
|
|
||||||
cat <<EOF >/run/systemd/system.attached/minimal-app0.service
|
|
||||||
[Unit]
|
|
||||||
Description=Minimal App 0
|
|
||||||
EOF
|
|
||||||
cat <<EOF >/run/systemd/system.attached/minimal-app0.service.d/10-profile.conf
|
|
||||||
[Unit]
|
|
||||||
Description=Minimal App 0
|
|
||||||
EOF
|
|
||||||
cat <<EOF >/run/systemd/system.attached/minimal-app0.service.d/20-portable.conf
|
|
||||||
[Unit]
|
|
||||||
Description=Minimal App 0
|
|
||||||
EOF
|
|
||||||
systemctl daemon-reload
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" attach --force --now --runtime /usr/share/minimal_0.raw minimal-app0
|
|
||||||
|
|
||||||
portablectl is-attached --force minimal-app0
|
|
||||||
portablectl inspect --force /usr/share/minimal_0.raw minimal-app0.service
|
|
||||||
systemctl is-active minimal-app0.service
|
|
||||||
systemctl is-active minimal-app0-foo.service
|
|
||||||
systemctl is-active minimal-app0-bar.service && exit 1
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" reattach --force --now --runtime /usr/share/minimal_1.raw minimal-app0
|
|
||||||
|
|
||||||
portablectl is-attached --force minimal-app0
|
|
||||||
portablectl inspect --force /usr/share/minimal_0.raw minimal-app0.service
|
|
||||||
systemctl is-active minimal-app0.service
|
|
||||||
systemctl is-active minimal-app0-bar.service
|
|
||||||
systemctl is-active minimal-app0-foo.service && exit 1
|
|
||||||
|
|
||||||
portablectl list | grep -q -F "minimal_1"
|
|
||||||
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1'
|
|
||||||
|
|
||||||
portablectl detach --force --now --runtime /usr/share/minimal_1.raw minimal-app0
|
|
||||||
|
|
||||||
portablectl list | grep -q -F "No images."
|
|
||||||
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' && exit 1
|
|
||||||
|
|
||||||
# portablectl also works with directory paths rather than images
|
|
||||||
|
|
||||||
unsquashfs -dest /tmp/minimal_0 /usr/share/minimal_0.raw
|
|
||||||
unsquashfs -dest /tmp/minimal_1 /usr/share/minimal_1.raw
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/minimal_0 minimal-app0
|
|
||||||
|
|
||||||
systemctl is-active minimal-app0.service
|
|
||||||
systemctl is-active minimal-app0-foo.service
|
|
||||||
systemctl is-active minimal-app0-bar.service && exit 1
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" reattach --now --enable --runtime /tmp/minimal_1 minimal-app0
|
|
||||||
|
|
||||||
systemctl is-active minimal-app0.service
|
|
||||||
systemctl is-active minimal-app0-bar.service
|
|
||||||
systemctl is-active minimal-app0-foo.service && exit 1
|
|
||||||
|
|
||||||
portablectl list | grep -q -F "minimal_1"
|
|
||||||
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1'
|
|
||||||
|
|
||||||
portablectl detach --now --enable --runtime /tmp/minimal_1 minimal-app0
|
|
||||||
|
|
||||||
portablectl list | grep -q -F "No images."
|
|
||||||
busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' && exit 1
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0
|
|
||||||
|
|
||||||
systemctl is-active app0.service
|
|
||||||
status="$(portablectl is-attached --extension app0 minimal_0)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_ROOT=minimal_0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_1.raw app0
|
|
||||||
|
|
||||||
systemctl is-active app0.service
|
|
||||||
status="$(portablectl is-attached --extension app0 minimal_1)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_ROOT=minimal_1.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
|
|
||||||
portablectl detach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_1.raw app0
|
|
||||||
|
|
||||||
# Ensure versioned images are accepted without needing to use --force to override the extension-release
|
|
||||||
# matching
|
|
||||||
|
|
||||||
cp /tmp/app0.raw /tmp/app0_1.0.raw
|
|
||||||
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app0_1.0.raw /usr/share/minimal_0.raw app0
|
|
||||||
|
|
||||||
systemctl is-active app0.service
|
|
||||||
status="$(portablectl is-attached --extension app0_1 minimal_0)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
portablectl detach --now --runtime --extension /tmp/app0_1.0.raw /usr/share/minimal_1.raw app0
|
|
||||||
rm -f /tmp/app0_1.0.raw
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1
|
|
||||||
|
|
||||||
systemctl is-active app1.service
|
|
||||||
status="$(portablectl is-attached --extension app1 minimal_0)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
# Ensure that adding or removing a version to the image doesn't break reattaching
|
|
||||||
cp /tmp/app1.raw /tmp/app1_2.raw
|
|
||||||
portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1_2.raw /usr/share/minimal_1.raw app1
|
|
||||||
|
|
||||||
systemctl is-active app1.service
|
|
||||||
status="$(portablectl is-attached --extension app1_2 minimal_1)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1.raw /usr/share/minimal_1.raw app1
|
|
||||||
|
|
||||||
systemctl is-active app1.service
|
|
||||||
status="$(portablectl is-attached --extension app1 minimal_1)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
portablectl detach --force --no-reload --runtime --extension /tmp/app1.raw /usr/share/minimal_1.raw app1
|
|
||||||
portablectl "${ARGS[@]}" attach --force --no-reload --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1
|
|
||||||
systemctl daemon-reload
|
|
||||||
systemctl restart app1.service
|
|
||||||
|
|
||||||
systemctl is-active app1.service
|
|
||||||
status="$(portablectl is-attached --extension app1 minimal_0)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
portablectl detach --now --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1
|
|
||||||
|
|
||||||
# Ensure vpick works, including reattaching to a new image
|
|
||||||
mkdir -p /tmp/app1.v/
|
|
||||||
cp /tmp/app1.raw /tmp/app1.v/app1_1.0.raw
|
|
||||||
cp /tmp/app1_2.raw /tmp/app1.v/app1_2.0.raw
|
|
||||||
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_1.raw app1
|
|
||||||
|
|
||||||
systemctl is-active app1.service
|
|
||||||
status="$(portablectl is-attached --extension app1_2.0.raw minimal_1)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
rm -f /tmp/app1.v/app1_2.0.raw
|
|
||||||
portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_1.raw app1
|
|
||||||
|
|
||||||
systemctl is-active app1.service
|
|
||||||
status="$(portablectl is-attached --extension app1_1.0.raw minimal_1)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
portablectl detach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_0.raw app1
|
|
||||||
rm -f /tmp/app1.v/app1_1.0.raw
|
|
||||||
|
|
||||||
# Ensure that the combination of read-only images, state directory and dynamic user works, and that
|
|
||||||
# state is retained. Check after detaching, as on slow systems (eg: sanitizers) it might take a while
|
|
||||||
# after the service is attached before the file appears.
|
|
||||||
grep -q -F bar "${STATE_DIRECTORY}/app0/foo"
|
|
||||||
grep -q -F baz "${STATE_DIRECTORY}/app1/foo"
|
|
||||||
|
|
||||||
# Ensure that we can override the check on extension-release.NAME
|
|
||||||
cp /tmp/app0.raw /tmp/app10.raw
|
|
||||||
portablectl "${ARGS[@]}" attach --force --now --runtime --extension /tmp/app10.raw /usr/share/minimal_0.raw app0
|
|
||||||
|
|
||||||
systemctl is-active app0.service
|
|
||||||
status="$(portablectl is-attached --extension /tmp/app10.raw /usr/share/minimal_0.raw)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
portablectl inspect --force --cat --extension /tmp/app10.raw /usr/share/minimal_0.raw app0 | grep -q -F "Extension Release: /tmp/app10.raw"
|
|
||||||
|
|
||||||
# Ensure that we can detach even when an image has been deleted already (stop the unit manually as
|
|
||||||
# portablectl won't find it)
|
|
||||||
rm -f /tmp/app10.raw
|
|
||||||
systemctl stop app0.service
|
|
||||||
portablectl detach --force --runtime --extension /tmp/app10.raw /usr/share/minimal_0.raw app0
|
|
||||||
|
|
||||||
# portablectl also accepts confexts
|
|
||||||
portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw app0
|
|
||||||
|
|
||||||
systemctl is-active app0.service
|
|
||||||
status="$(portablectl is-attached --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw)"
|
|
||||||
[[ "${status}" == "running-runtime" ]]
|
|
||||||
|
|
||||||
portablectl inspect --force --cat --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw app0 | grep -q -F "Extension Release: /tmp/conf0.raw"
|
|
||||||
|
|
||||||
portablectl detach --now --runtime --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw app0
|
|
||||||
|
|
||||||
# Ensure that mixed mode copies the images and units (client-owned) but symlinks the profile (OS owned)
|
|
||||||
portablectl "${ARGS[@]}" attach --copy=mixed --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0
|
|
||||||
test -f /run/portables/app0.raw
|
|
||||||
test -f /run/portables/minimal_0.raw
|
|
||||||
test -f /run/systemd/system.attached/app0.service
|
|
||||||
test -L /run/systemd/system.attached/app0.service.d/10-profile.conf
|
|
||||||
portablectl detach --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0
|
|
||||||
|
|
||||||
# Ensure that when two portables share the same base image, removing one doesn't remove the other too
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" attach --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0
|
|
||||||
portablectl "${ARGS[@]}" attach --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1
|
|
||||||
|
|
||||||
status="$(portablectl is-attached --extension app0 minimal_0)"
|
|
||||||
[[ "${status}" == "attached-runtime" ]]
|
|
||||||
status="$(portablectl is-attached --extension app1 minimal_0)"
|
|
||||||
[[ "${status}" == "attached-runtime" ]]
|
|
||||||
|
|
||||||
(! portablectl detach --runtime /usr/share/minimal_0.raw app)
|
|
||||||
|
|
||||||
status="$(portablectl is-attached --extension app0 minimal_0)"
|
|
||||||
[[ "${status}" == "attached-runtime" ]]
|
|
||||||
status="$(portablectl is-attached --extension app1 minimal_0)"
|
|
||||||
[[ "${status}" == "attached-runtime" ]]
|
|
||||||
|
|
||||||
# Ensure 'portablectl list' shows the correct status for both images
|
|
||||||
portablectl list
|
|
||||||
portablectl list | grep -F "minimal_0" | grep -q -F "attached-runtime"
|
|
||||||
portablectl list | grep -F "app0" | grep -q -F "attached-runtime"
|
|
||||||
portablectl list | grep -F "app1" | grep -q -F "attached-runtime"
|
|
||||||
|
|
||||||
portablectl detach --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app
|
|
||||||
|
|
||||||
status="$(portablectl is-attached --extension app1 minimal_0)"
|
|
||||||
[[ "${status}" == "attached-runtime" ]]
|
|
||||||
|
|
||||||
portablectl detach --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app
|
|
||||||
|
|
||||||
# portablectl also works with directory paths rather than images
|
|
||||||
|
|
||||||
mkdir /tmp/rootdir /tmp/app0 /tmp/app1 /tmp/overlay /tmp/os-release-fix /tmp/os-release-fix/etc
|
|
||||||
mount /tmp/app0.raw /tmp/app0
|
|
||||||
mount /tmp/app1.raw /tmp/app1
|
|
||||||
mount /usr/share/minimal_0.raw /tmp/rootdir
|
|
||||||
|
|
||||||
# Fix up os-release to drop the valid PORTABLE_SERVICES field (because we are
|
|
||||||
# bypassing the sysext logic in portabled here it will otherwise not see the
|
|
||||||
# extensions additional valid prefix)
|
|
||||||
grep -v "^PORTABLE_PREFIXES=" /tmp/rootdir/etc/os-release >/tmp/os-release-fix/etc/os-release
|
|
||||||
|
|
||||||
mount -t overlay overlay -o lowerdir=/tmp/os-release-fix:/tmp/app1:/tmp/rootdir /tmp/overlay
|
|
||||||
|
|
||||||
grep . /tmp/overlay/usr/lib/extension-release.d/*
|
|
||||||
grep . /tmp/overlay/etc/os-release
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/overlay app1
|
|
||||||
|
|
||||||
systemctl is-active app1.service
|
|
||||||
|
|
||||||
portablectl detach --now --runtime overlay app1
|
|
||||||
|
|
||||||
# Ensure --force works also when symlinking
|
|
||||||
mkdir -p /run/systemd/system.attached/app1.service.d
|
|
||||||
cat <<EOF >/run/systemd/system.attached/app1.service
|
|
||||||
[Unit]
|
|
||||||
Description=App 1
|
|
||||||
EOF
|
|
||||||
cat <<EOF >/run/systemd/system.attached/app1.service.d/10-profile.conf
|
|
||||||
[Unit]
|
|
||||||
Description=App 1
|
|
||||||
EOF
|
|
||||||
cat <<EOF >/run/systemd/system.attached/app1.service.d/20-portable.conf
|
|
||||||
[Unit]
|
|
||||||
Description=App 1
|
|
||||||
EOF
|
|
||||||
systemctl daemon-reload
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" attach --force --copy=symlink --now --runtime /tmp/overlay app1
|
|
||||||
|
|
||||||
systemctl is-active app1.service
|
|
||||||
|
|
||||||
portablectl detach --now --runtime overlay app1
|
|
||||||
|
|
||||||
umount /tmp/overlay
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1
|
|
||||||
|
|
||||||
systemctl is-active app0.service
|
|
||||||
systemctl is-active app1.service
|
|
||||||
|
|
||||||
portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/rootdir/usr/lib/os-release
|
|
||||||
portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app0/usr/lib/extension-release.d/extension-release.app0
|
|
||||||
portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app1/usr/lib/extension-release.d/extension-release.app2
|
|
||||||
portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app1/usr/lib/systemd/system/app1.service
|
|
||||||
portablectl inspect --cat --extension app0 --extension app1 rootdir app0 app1 | grep -q -f /tmp/app0/usr/lib/systemd/system/app0.service
|
|
||||||
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE=app0" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_ROOT=rootdir" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app1" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app_1" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
|
||||||
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE=app1" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_ROOT=rootdir" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app1" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app_1" /run/systemd/system.attached/app1.service.d/20-portable.conf
|
|
||||||
|
|
||||||
portablectl detach --clean --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1
|
|
||||||
|
|
||||||
# Ensure --clean remove state and other directories belonging to the portable image being detached
|
|
||||||
test ! -d /var/lib/app0
|
|
||||||
test ! -d /run/app0
|
|
||||||
|
|
||||||
# Ensure that mixed mode copies the images and units (client-owned) but symlinks the profile (OS owned)
|
|
||||||
portablectl "${ARGS[@]}" attach --copy=mixed --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1
|
|
||||||
test -d /run/portables/app0
|
|
||||||
test -d /run/portables/app1
|
|
||||||
test -d /run/portables/rootdir
|
|
||||||
test -f /run/systemd/system.attached/app0.service
|
|
||||||
test -f /run/systemd/system.attached/app1.service
|
|
||||||
test -L /run/systemd/system.attached/app0.service.d/10-profile.conf
|
|
||||||
test -L /run/systemd/system.attached/app1.service.d/10-profile.conf
|
|
||||||
portablectl detach --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1
|
|
||||||
|
|
||||||
# Attempt to disable the app unit during detaching. Requires --copy=symlink to reproduce.
|
|
||||||
# Provides coverage for https://github.com/systemd/systemd/issues/23481
|
|
||||||
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/rootdir minimal-app0
|
|
||||||
portablectl detach --now --runtime --enable /tmp/rootdir minimal-app0
|
|
||||||
# attach and detach again to check if all drop-in configs are removed even if the main unit files are removed
|
|
||||||
portablectl "${ARGS[@]}" attach --copy=symlink --now --runtime /tmp/rootdir minimal-app0
|
|
||||||
portablectl detach --now --runtime --enable /tmp/rootdir minimal-app0
|
|
||||||
|
|
||||||
# The wrong file should be ignored, given the right one has the xattr set
|
|
||||||
trap 'rm -rf /var/cache/wrongext' EXIT
|
|
||||||
mkdir -p /var/cache/wrongext/usr/lib/extension-release.d /var/cache/wrongext/usr/lib/systemd/system/
|
|
||||||
echo "[Service]" > /var/cache/wrongext/usr/lib/systemd/system/app0.service
|
|
||||||
touch /var/cache/wrongext/usr/lib/extension-release.d/extension-release.wrongext_somethingwrong.txt
|
|
||||||
cp /tmp/rootdir/usr/lib/os-release /var/cache/wrongext/usr/lib/extension-release.d/extension-release.app0
|
|
||||||
setfattr -n user.extension-release.strict -v "false" /var/cache/wrongext/usr/lib/extension-release.d/extension-release.app0
|
|
||||||
portablectl "${ARGS[@]}" attach --runtime --extension /var/cache/wrongext /tmp/rootdir app0
|
|
||||||
status="$(portablectl is-attached --extension wrongext rootdir)"
|
|
||||||
[[ "${status}" == "attached-runtime" ]]
|
|
||||||
portablectl detach --runtime --extension /var/cache/wrongext /tmp/rootdir app0
|
|
||||||
|
|
||||||
umount /tmp/rootdir
|
|
||||||
umount /tmp/app0
|
|
||||||
umount /tmp/app1
|
|
||||||
|
|
||||||
# Lack of ID field in os-release should be rejected, but it caused a crash in the past instead
|
# Lack of ID field in os-release should be rejected, but it caused a crash in the past instead
|
||||||
mkdir -p /tmp/emptyroot/usr/lib
|
mkdir -p /tmp/emptyroot/usr/lib
|
||||||
mkdir -p /tmp/emptyext/usr/lib/extension-release.d
|
mkdir -p /tmp/emptyext/usr/lib/extension-release.d
|
||||||
|
@ -417,4 +63,8 @@ touch /tmp/emptyext/usr/lib/extension-release.d/extension-release.emptyext
|
||||||
res="$(! portablectl attach --extension /tmp/emptyext /tmp/emptyroot 2> >(grep "Remote peer disconnected"))"
|
res="$(! portablectl attach --extension /tmp/emptyext /tmp/emptyroot 2> >(grep "Remote peer disconnected"))"
|
||||||
test -z "${res}"
|
test -z "${res}"
|
||||||
|
|
||||||
|
: "Run subtests"
|
||||||
|
|
||||||
|
run_subtests
|
||||||
|
|
||||||
touch /testok
|
touch /testok
|
||||||
|
|
|
@ -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