Compare commits
1 Commits
3080dba979
...
1f8f97c438
Author | SHA1 | Date |
---|---|---|
Philip Meulengracht | 1f8f97c438 |
13
NEWS
13
NEWS
|
@ -2,15 +2,6 @@ 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
|
||||||
|
@ -94,7 +85,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 re-enabled during late shutdown, so that the user
|
* Ctrl-Alt-Delete is reenabled 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
|
||||||
|
@ -211,7 +202,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 configured with
|
directory to which transfer sources cofigured with
|
||||||
PathRelativeTo=explicit will be interpreted.
|
PathRelativeTo=explicit will be interpreted.
|
||||||
|
|
||||||
Miscellaneous:
|
Miscellaneous:
|
||||||
|
|
12
TODO
12
TODO
|
@ -130,10 +130,6 @@ 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.
|
||||||
|
|
||||||
|
@ -999,6 +995,12 @@ 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
|
||||||
|
|
||||||
|
@ -1499,8 +1501,6 @@ Features:
|
||||||
|
|
||||||
* systemd-analyze netif that explains predictable interface (or networkctl)
|
* systemd-analyze netif that explains predictable interface (or networkctl)
|
||||||
|
|
||||||
* systemd-analyze inspect-elf should show other notes too, at least build-id.
|
|
||||||
|
|
||||||
* Figure out naming of verbs in systemd-analyze: we have (singular) capability,
|
* Figure out naming of verbs in systemd-analyze: we have (singular) capability,
|
||||||
exit-status, but (plural) filesystems, architectures.
|
exit-status, but (plural) filesystems, architectures.
|
||||||
|
|
||||||
|
|
|
@ -87,90 +87,3 @@ of the libraries they specify in order to be enabled.
|
||||||
| required | Core functionality needs the dependency, the binary will not work if it cannot be found |
|
| required | Core functionality needs the dependency, the binary will not work if it cannot be found |
|
||||||
| recommended | Important functionality needs the dependency, the binary will work but in most cases the dependency should be provided |
|
| recommended | Important functionality needs the dependency, the binary will work but in most cases the dependency should be provided |
|
||||||
| suggested | Secondary functionality needs the dependency, the binary will work and the dependency is only needed for full-featured installations |
|
| suggested | Secondary functionality needs the dependency, the binary will work and the dependency is only needed for full-featured installations |
|
||||||
|
|
||||||
### Displaying `dlopen()` notes
|
|
||||||
|
|
||||||
The raw ELF section can be extracted using `objdump`:
|
|
||||||
```console
|
|
||||||
$ objdump -j .note.dlopen -s /usr/lib64/systemd/libsystemd-shared-257.so
|
|
||||||
|
|
||||||
/usr/lib64/systemd/libsystemd-shared-257.so: file format elf64-x86-64
|
|
||||||
|
|
||||||
Contents of section .note.dlopen:
|
|
||||||
0334 04000000 8e000000 0a0c7c40 46444f00 ..........|@FDO.
|
|
||||||
0344 5b7b2266 65617475 7265223a 22627066 [{"feature":"bpf
|
|
||||||
0354 222c2264 65736372 69707469 6f6e223a ","description":
|
|
||||||
0364 22537570 706f7274 20666972 6577616c "Support firewal
|
|
||||||
0374 6c696e67 20616e64 2073616e 64626f78 ling and sandbox
|
|
||||||
0384 696e6720 77697468 20425046 222c2270 ing with BPF","p
|
|
||||||
0394 72696f72 69747922 3a227375 67676573 riority":"sugges
|
|
||||||
03a4 74656422 2c22736f 6e616d65 223a5b22 ted","soname":["
|
|
||||||
03b4 6c696262 70662e73 6f2e3122 2c226c69 libbpf.so.1","li
|
|
||||||
03c4 62627066 2e736f2e 30225d7d 5d000000 bbpf.so.0"]}]...
|
|
||||||
03d4 04000000 9e000000 0a0c7c40 46444f00 ..........|@FDO.
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
It is more convenient to use a higher level tool:
|
|
||||||
```console
|
|
||||||
$ dlopen-notes /usr/lib64/systemd/libsystemd-shared-257.so
|
|
||||||
# /usr/lib64/systemd/libsystemd-shared-257.so
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"feature": "archive",
|
|
||||||
"description": "Support for decompressing archive files",
|
|
||||||
"priority": "suggested",
|
|
||||||
"soname": [
|
|
||||||
"libarchive.so.13"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"feature": "bpf",
|
|
||||||
"description": "Support firewalling and sandboxing with BPF",
|
|
||||||
"priority": "suggested",
|
|
||||||
"soname": [
|
|
||||||
"libbpf.so.1",
|
|
||||||
"libbpf.so.0"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
`dlopen-notes` can display the notes grouped in a few different ways.
|
|
||||||
One option is to filter the libraries by "feature". This answers the
|
|
||||||
question "what libraries are needed to provide specified features":
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ dlopen-notes.py -f archive,bpf /usr/lib64/systemd/libsystemd-shared-257.so
|
|
||||||
# grouped by feature
|
|
||||||
{
|
|
||||||
"bpf": {
|
|
||||||
"description": "Support firewalling and sandboxing with BPF",
|
|
||||||
"sonames": {
|
|
||||||
"libbpf.so.1": "suggested",
|
|
||||||
"libbpf.so.0": "suggested"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"archive": {
|
|
||||||
"description": "Support for decompressing archive files",
|
|
||||||
"sonames": {
|
|
||||||
"libarchive.so.13": "suggested"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
The format that is used when building `deb` packages:
|
|
||||||
```console
|
|
||||||
$ dlopen-notes -s /usr/lib64/systemd/libsystemd-shared-257.so
|
|
||||||
libarchive.so.13 suggested
|
|
||||||
libbpf.so.0 suggested
|
|
||||||
libbpf.so.1 suggested
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
The format that can be useful when building `rpm` packages:
|
|
||||||
```console
|
|
||||||
$ dlopen-notes --rpm-requires archive --rpm-recommends bpf /usr/lib64/systemd/libsystemd-shared-257.so
|
|
||||||
Requires: libarchive.so.13()(64bit)
|
|
||||||
Recommends: libbpf.so.1()(64bit)
|
|
||||||
```
|
|
||||||
|
|
|
@ -103,97 +103,3 @@ A set of well-known keys is defined here, and hopefully shared among all vendors
|
||||||
| architecture | The binary package architecture | arm32 |
|
| architecture | The binary package architecture | arm32 |
|
||||||
| osCpe | A CPE name for the OS, typically corresponding to CPE_NAME in os-release | cpe:/o:fedoraproject:fedora:33 |
|
| osCpe | A CPE name for the OS, typically corresponding to CPE_NAME in os-release | cpe:/o:fedoraproject:fedora:33 |
|
||||||
| debugInfoUrl | The debuginfod server url, if available | https://debuginfod.fedoraproject.org/ |
|
| debugInfoUrl | The debuginfod server url, if available | https://debuginfod.fedoraproject.org/ |
|
||||||
|
|
||||||
### Displaying package notes
|
|
||||||
|
|
||||||
The raw ELF section can be extracted using `objdump`:
|
|
||||||
```console
|
|
||||||
$ objdump -j .note.package -s /usr/bin/ls
|
|
||||||
|
|
||||||
/usr/bin/ls: file format elf64-x86-64
|
|
||||||
|
|
||||||
Contents of section .note.package:
|
|
||||||
03cc 04000000 7c000000 7e1afeca 46444f00 ....|...~...FDO.
|
|
||||||
03dc 7b227479 7065223a 2272706d 222c226e {"type":"rpm","n
|
|
||||||
03ec 616d6522 3a22636f 72657574 696c7322 ame":"coreutils"
|
|
||||||
03fc 2c227665 7273696f 6e223a22 392e342d ,"version":"9.4-
|
|
||||||
040c 372e6663 3430222c 22617263 68697465 7.fc40","archite
|
|
||||||
041c 63747572 65223a22 7838365f 3634222c cture":"x86_64",
|
|
||||||
042c 226f7343 7065223a 22637065 3a2f6f3a "osCpe":"cpe:/o:
|
|
||||||
043c 6665646f 72617072 6f6a6563 743a6665 fedoraproject:fe
|
|
||||||
044c 646f7261 3a343022 7d000000 dora:40"}...
|
|
||||||
```
|
|
||||||
|
|
||||||
It is more convenient to use a higher level tool:
|
|
||||||
```console
|
|
||||||
$ readelf --notes /usr/bin/ls
|
|
||||||
...
|
|
||||||
Displaying notes found in: .note.gnu.build-id
|
|
||||||
Owner Data size Description
|
|
||||||
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
|
|
||||||
Build ID: 40e5a1570a9d97fc48f5c61cfb7690fec0f872b2
|
|
||||||
|
|
||||||
Displaying notes found in: .note.ABI-tag
|
|
||||||
Owner Data size Description
|
|
||||||
GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag)
|
|
||||||
OS: Linux, ABI: 3.2.0
|
|
||||||
|
|
||||||
Displaying notes found in: .note.package
|
|
||||||
Owner Data size Description
|
|
||||||
FDO 0x0000007c FDO_PACKAGING_METADATA
|
|
||||||
Packaging Metadata: {"type":"rpm","name":"coreutils","version":"9.4-7.fc40","architecture":"x86_64","osCpe":"cpe:/o:fedoraproject:fedora:40"}
|
|
||||||
...
|
|
||||||
|
|
||||||
$ systemd-analyze inspect-elf /usr/bin/ls
|
|
||||||
path: /usr/bin/ls
|
|
||||||
elfType: executable
|
|
||||||
elfArchitecture: AMD x86-64
|
|
||||||
|
|
||||||
type: rpm
|
|
||||||
name: coreutils
|
|
||||||
version: 9.4-7.fc40
|
|
||||||
architecture: x86_64
|
|
||||||
osCpe: cpe:/o:fedoraproject:fedora:40
|
|
||||||
buildId: 40e5a1570a9d97fc48f5c61cfb7690fec0f872b2
|
|
||||||
```
|
|
||||||
|
|
||||||
If the binary crashes, `systemd-coredump` will display the combined information
|
|
||||||
from the crashing binary and any shared libraries it links to:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ coredumpctl info
|
|
||||||
PID: 3987823 (ls)
|
|
||||||
Signal: 11 (SEGV)
|
|
||||||
Command Line: ls --color=tty -lR /
|
|
||||||
Executable: /usr/bin/ls
|
|
||||||
...
|
|
||||||
Storage: /var/lib/systemd/coredump/core.ls.1000.88dea1b9831c420dbb398f9d2ad9b41e.3987823.1726230641000000.zst (present)
|
|
||||||
Size on Disk: 194.4K
|
|
||||||
Package: coreutils/9.4-7.fc40
|
|
||||||
build-id: 40e5a1570a9d97fc48f5c61cfb7690fec0f872b2
|
|
||||||
Message: Process 3987823 (ls) of user 1000 dumped core.
|
|
||||||
|
|
||||||
Module /usr/bin/ls from rpm coreutils-9.4-7.fc40.x86_64
|
|
||||||
Module libz.so.1 from rpm zlib-ng-2.1.7-1.fc40.x86_64
|
|
||||||
Module libcrypto.so.3 from rpm openssl-3.2.2-3.fc40.x86_64
|
|
||||||
Module libmount.so.1 from rpm util-linux-2.40.1-1.fc40.x86_64
|
|
||||||
Module libcrypt.so.2 from rpm libxcrypt-4.4.36-5.fc40.x86_64
|
|
||||||
Module libblkid.so.1 from rpm util-linux-2.40.1-1.fc40.x86_64
|
|
||||||
Module libnss_sss.so.2 from rpm sssd-2.9.5-1.fc40.x86_64
|
|
||||||
Module libpcre2-8.so.0 from rpm pcre2-10.44-1.fc40.x86_64
|
|
||||||
Module libcap.so.2 from rpm libcap-2.69-8.fc40.x86_64
|
|
||||||
Module libselinux.so.1 from rpm libselinux-3.6-4.fc40.x86_64
|
|
||||||
Stack trace of thread 3987823:
|
|
||||||
#0 0x00007f19331c3f7e lgetxattr (libc.so.6 + 0x116f7e)
|
|
||||||
#1 0x00007f19332be4c0 lgetfilecon_raw (libselinux.so.1 + 0x134c0)
|
|
||||||
#2 0x00007f19332c3bd9 lgetfilecon (libselinux.so.1 + 0x18bd9)
|
|
||||||
#3 0x000056038273ad55 gobble_file.constprop.0 (/usr/bin/ls + 0x17d55)
|
|
||||||
#4 0x0000560382733c55 print_dir (/usr/bin/ls + 0x10c55)
|
|
||||||
#5 0x0000560382727c35 main (/usr/bin/ls + 0x4c35)
|
|
||||||
#6 0x00007f19330d7088 __libc_start_call_main (libc.so.6 + 0x2a088)
|
|
||||||
#7 0x00007f19330d714b __libc_start_main@@GLIBC_2.34 (libc.so.6 + 0x2a14b)
|
|
||||||
#8 0x0000560382728f15 _start (/usr/bin/ls + 0x5f15)
|
|
||||||
ELF object binary architecture: AMD x86-64
|
|
||||||
```
|
|
||||||
|
|
||||||
(This is just a simulation. `ls` is not prone to crashing with a segmentation violation.)
|
|
||||||
|
|
|
@ -299,10 +299,6 @@ 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:*
|
||||||
|
@ -607,15 +603,6 @@ 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,10 +310,6 @@ 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,8 +267,7 @@
|
||||||
<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>addon</literal>, <literal>pe</literal>, and
|
one of <literal>uki</literal>, <literal>pe</literal>, and <literal>unknown</literal>.
|
||||||
<literal>unknown</literal>.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
|
||||||
|
@ -361,24 +360,6 @@
|
||||||
<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,10 +46,11 @@
|
||||||
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 all non-busy file systems (detaching
|
<para>On shutdown, the system manager stops all services, unmounts
|
||||||
the storage technologies backing them), and then (optionally) jumps into the exitrd, which is backed by
|
all file systems (detaching the storage technologies backing
|
||||||
tmpfs, and unmounts/detaches the remaining file systems, including the real root. As a last step,
|
them), and then (optionally) jumps back into the initrd code which
|
||||||
the system is powered down.</para>
|
unmounts/detaches the root file system and the storage it resides
|
||||||
|
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 overridden) are
|
the PE sections of the selected profile (and those of the base profile, except if overriden) 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,11 +152,10 @@
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--purge</option></term>
|
<term><option>--purge</option></term>
|
||||||
|
|
||||||
<listitem><para>If this option is passed, all files and directories declared for
|
<listitem><para>If this option is passed, all files and directories marked for
|
||||||
<emphasis>creation</emphasis> and marked with the <literal>$</literal> character by the
|
<emphasis>creation</emphasis> by the <filename>tmpfiles.d/</filename> files specified on the command
|
||||||
<filename>tmpfiles.d/</filename> files specified on the command line will be
|
line will be <emphasis>deleted</emphasis>. Specifically, this acts on all files and directories
|
||||||
<emphasis>deleted</emphasis>. Specifically, this acts on all files and directories marked with
|
marked with <varname>f</varname>, <varname>F</varname>, <varname>d</varname>, <varname>D</varname>,
|
||||||
<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,10 +539,6 @@ 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,12 +141,6 @@
|
||||||
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,6 +58,9 @@ 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" \
|
||||||
|
@ -65,11 +68,9 @@ 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,12 +221,6 @@ 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
|
||||||
|
@ -253,7 +247,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,10 +145,8 @@ 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;
|
||||||
char *x;
|
|
||||||
int r;
|
int r;
|
||||||
|
char *x;
|
||||||
assert(variable);
|
|
||||||
|
|
||||||
r = efi_get_variable(variable, NULL, &s, &ss);
|
r = efi_get_variable(variable, NULL, &s, &ss);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -158,27 +156,10 @@ int efi_get_variable_string(const char *variable, char **ret) {
|
||||||
if (!x)
|
if (!x)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (ret)
|
*ret = x;
|
||||||
*ret = x;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int efi_get_variable_path(const char *variable, char **ret) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(variable);
|
|
||||||
|
|
||||||
r = efi_get_variable_string(variable, ret);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
efi_tilt_backslashes(*ret);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int efi_verify_variable(const char *variable, uint32_t attr, const void *value, size_t size) {
|
static int efi_verify_variable(const char *variable, uint32_t attr, const void *value, size_t size) {
|
||||||
_cleanup_free_ void *buf = NULL;
|
_cleanup_free_ void *buf = NULL;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#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)
|
||||||
|
@ -48,7 +47,6 @@
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
@ -70,10 +68,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +100,3 @@ 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 *ret_old_mask, ...);
|
int sigprocmask_many_internal(int how, sigset_t *old, ...);
|
||||||
#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,12 +219,14 @@ static int acquire_boot_count_path(
|
||||||
uint64_t left, done;
|
uint64_t left, done;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = efi_get_variable_path(EFI_LOADER_VARIABLE(LoaderBootCountPath), &path);
|
r = efi_get_variable_string(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,24 +298,12 @@ fail:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int efi_get_variable_string_and_warn(const char *variable, char **ret) {
|
static void read_efi_var(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)
|
||||||
return log_warning_errno(r, "Failed to read EFI variable '%s', ignoring: %m", variable);
|
log_warning_errno(r, "Failed to read EFI variable %s: %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) {
|
||||||
|
@ -408,23 +396,26 @@ 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, *stub_path = NULL,
|
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
|
||||||
*current_entry = NULL, *oneshot_entry = NULL, *default_entry = NULL;
|
sd_id128_t loader_part_uuid = SD_ID128_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;
|
||||||
|
|
||||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
|
read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
|
||||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
|
read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
|
||||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
|
read_efi_var(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
|
||||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(StubInfo), &stub);
|
read_efi_var(EFI_LOADER_VARIABLE(StubInfo), &stub);
|
||||||
(void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &loader_path);
|
read_efi_var(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);
|
|
||||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &oneshot_entry);
|
if (loader_path)
|
||||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntryDefault), &default_entry);
|
efi_tilt_backslashes(loader_path);
|
||||||
|
|
||||||
|
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());
|
||||||
|
@ -472,58 +463,34 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
if (loader) {
|
printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
|
||||||
printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
|
printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal());
|
||||||
printf(" Product: %s%s%s\n", ansi_highlight(), loader, ansi_normal());
|
|
||||||
for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
|
|
||||||
print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
|
|
||||||
|
|
||||||
sd_id128_t loader_partition_uuid;
|
for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
|
||||||
bool have_loader_partition_uuid = efi_loader_get_device_part_uuid(&loader_partition_uuid) >= 0;
|
print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
|
||||||
|
|
||||||
print_yes_no_line(false, have_loader_partition_uuid, "Boot loader set ESP information");
|
sd_id128_t bootloader_esp_uuid;
|
||||||
|
bool have_bootloader_esp_uuid = efi_loader_get_device_part_uuid(&bootloader_esp_uuid) >= 0;
|
||||||
|
|
||||||
if (current_entry)
|
print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP information");
|
||||||
printf("Current Entry: %s\n", current_entry);
|
if (have_bootloader_esp_uuid && !sd_id128_is_null(esp_uuid) &&
|
||||||
if (default_entry)
|
!sd_id128_equal(esp_uuid, bootloader_esp_uuid))
|
||||||
printf("Default Entry: %s\n", 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",
|
||||||
if (oneshot_entry && !streq_ptr(oneshot_entry, default_entry))
|
SD_ID128_FORMAT_VAL(bootloader_esp_uuid),
|
||||||
printf("OneShot Entry: %s\n", oneshot_entry);
|
SD_ID128_FORMAT_VAL(esp_uuid));
|
||||||
|
|
||||||
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("%sCurrent Stub:%s\n", ansi_underline(), ansi_normal());
|
printf(" Stub: %s\n", stub);
|
||||||
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,14 +16,12 @@
|
||||||
#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"
|
||||||
|
@ -40,8 +38,6 @@ 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;
|
||||||
|
@ -137,71 +133,6 @@ 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;
|
||||||
|
@ -251,9 +182,6 @@ 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"
|
||||||
|
@ -307,8 +235,6 @@ 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[] = {
|
||||||
|
@ -324,8 +250,6 @@ 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 },
|
||||||
|
@ -408,14 +332,6 @@ 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;
|
||||||
|
@ -498,9 +414,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) + arg_print_loader_path + arg_print_stub_path > 1)
|
if (!!arg_print_esp_path + !!arg_print_dollar_boot_path + (arg_print_root_device > 0) > 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, --print-loader-path, --print-stub-path cannot be combined.");
|
"--print-esp-path/-p, --print-boot-path/-x, --print-root-device=/-R 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"))
|
||||||
|
@ -625,9 +541,6 @@ 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,7 +13,6 @@
|
||||||
#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"
|
||||||
|
@ -2421,18 +2420,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,
|
||||||
Pages *ret_initrd_pages,
|
void **ret_initrd,
|
||||||
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_pages);
|
assert(ret_initrd);
|
||||||
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_pages = (Pages) {};
|
*ret_initrd = NULL;
|
||||||
*ret_initrd_size = 0;
|
*ret_initrd_size = 0;
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2446,6 +2445,7 @@ 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,58 +2464,30 @@ 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 read_size = info->FileSize;
|
size_t new_size, read_size = info->FileSize;
|
||||||
err = chunked_read(handle, &read_size, p);
|
if (!ADD_SAFE(&new_size, size, read_size))
|
||||||
|
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(read_size == info->FileSize);
|
assert(size + read_size == new_size);
|
||||||
p += read_size;
|
size = new_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_pages = TAKE_STRUCT(pages);
|
*ret_initrd = TAKE_PTR(initrd);
|
||||||
*ret_initrd_size = size;
|
*ret_initrd_size = size;
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2545,9 +2517,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_pages_ Pages initrd_pages = {};
|
_cleanup_free_ void *initrd = NULL;
|
||||||
_cleanup_free_ char16_t *options_initrd = NULL;
|
_cleanup_free_ char16_t *options_initrd = NULL;
|
||||||
err = initrd_prepare(image_root, entry, &options_initrd, &initrd_pages, &initrd_size);
|
err = initrd_prepare(image_root, entry, &options_initrd, &initrd, &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");
|
||||||
|
|
||||||
|
@ -2565,7 +2537,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(PHYSICAL_ADDRESS_TO_POINTER(initrd_pages.addr), initrd_size, &initrd_handle);
|
err = initrd_register(initrd, 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,8 +134,9 @@ 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 = TAKE_STRUCT(pages);
|
*ret_initrd_pages = pages;
|
||||||
*ret_initrd_size = n;
|
*ret_initrd_size = n;
|
||||||
|
pages.n_pages = 0;
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2728,7 +2728,6 @@ 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;; ) {
|
||||||
|
|
|
@ -528,15 +528,11 @@ static int append_extensions(
|
||||||
&result);
|
&result);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (!result.path) {
|
if (!result.path)
|
||||||
if (m->ignore_enoent)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return log_debug_errno(
|
return log_debug_errno(
|
||||||
SYNTHETIC_ERRNO(ENOENT),
|
SYNTHETIC_ERRNO(ENOENT),
|
||||||
"No matching entry in .v/ directory %s found.",
|
"No matching entry in .v/ directory %s found.",
|
||||||
m->source);
|
m->source);
|
||||||
}
|
|
||||||
|
|
||||||
r = verity_settings_load(&verity, result.path, /* root_hash_path= */ NULL, /* root_hash_sig_path= */ NULL);
|
r = verity_settings_load(&verity, result.path, /* root_hash_path= */ NULL, /* root_hash_sig_path= */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -579,6 +575,10 @@ static int append_extensions(
|
||||||
const char *e = *extension_directory;
|
const char *e = *extension_directory;
|
||||||
bool ignore_enoent = false;
|
bool ignore_enoent = false;
|
||||||
|
|
||||||
|
/* Pick up the counter where the ExtensionImages left it. */
|
||||||
|
if (asprintf(&mount_point, "%s/unit-extensions/%zu", private_namespace_dir, n_mount_images++) < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Look for any prefixes */
|
/* Look for any prefixes */
|
||||||
if (startswith(e, "-")) {
|
if (startswith(e, "-")) {
|
||||||
e++;
|
e++;
|
||||||
|
@ -596,19 +596,11 @@ static int append_extensions(
|
||||||
&result);
|
&result);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (!result.path) {
|
if (!result.path)
|
||||||
if (ignore_enoent)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return log_debug_errno(
|
return log_debug_errno(
|
||||||
SYNTHETIC_ERRNO(ENOENT),
|
SYNTHETIC_ERRNO(ENOENT),
|
||||||
"No matching entry in .v/ directory %s found.",
|
"No matching entry in .v/ directory %s found.",
|
||||||
e);
|
e);
|
||||||
}
|
|
||||||
|
|
||||||
/* Pick up the counter where the ExtensionImages left it. */
|
|
||||||
if (asprintf(&mount_point, "%s/unit-extensions/%zu", private_namespace_dir, n_mount_images++) < 0)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
for (size_t j = 0; hierarchies && hierarchies[j]; ++j) {
|
for (size_t j = 0; hierarchies && hierarchies[j]; ++j) {
|
||||||
char *prefixed_hierarchy = path_join(mount_point, hierarchies[j]);
|
char *prefixed_hierarchy = path_join(mount_point, hierarchies[j]);
|
||||||
|
|
|
@ -1046,6 +1046,7 @@ 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;
|
||||||
|
|
||||||
|
@ -1062,7 +1063,8 @@ static int process_socket(int fd) {
|
||||||
.msg_controllen = sizeof(control),
|
.msg_controllen = sizeof(control),
|
||||||
.msg_iovlen = 1,
|
.msg_iovlen = 1,
|
||||||
};
|
};
|
||||||
ssize_t n, l;
|
ssize_t n;
|
||||||
|
ssize_t l;
|
||||||
|
|
||||||
l = next_datagram_size_fd(fd);
|
l = next_datagram_size_fd(fd);
|
||||||
if (l < 0) {
|
if (l < 0) {
|
||||||
|
@ -1070,10 +1072,8 @@ static int process_socket(int fd) {
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec iovec = {
|
iovec.iov_len = l;
|
||||||
.iov_len = l,
|
iovec.iov_base = malloc(l + 1);
|
||||||
.iov_base = malloc(l + 1),
|
|
||||||
};
|
|
||||||
if (!iovec.iov_base) {
|
if (!iovec.iov_base) {
|
||||||
r = log_oom();
|
r = log_oom();
|
||||||
goto finish;
|
goto finish;
|
||||||
|
@ -1083,6 +1083,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -1092,6 +1093,8 @@ 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;
|
||||||
|
@ -1131,8 +1134,6 @@ 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,6 +7,7 @@
|
||||||
#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"
|
||||||
|
@ -69,11 +70,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);
|
||||||
|
@ -714,9 +715,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"
|
||||||
|
@ -1046,7 +1047,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 }, /* for backward compatibility */
|
{ "has-tpm2", VERB_ANY, 1, 0, verb_has_tpm2 },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,25 +31,3 @@ 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,16 +222,20 @@ int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_set_signal_exit(m->event, true);
|
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_memory_pressure(m->event, /* ret_event_source= */ NULL, /* callback= */ NULL, /* userdata= */ NULL);
|
r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, 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, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata = */ NULL);
|
r = sd_event_add_signal(m->event, NULL, SIGRTMIN+18, sigrtmin18_handler, 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, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
|
||||||
|
|
||||||
r = manager_new(&m);
|
r = manager_new(&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -1784,15 +1784,17 @@ static int server_setup_signals(Server *s) {
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigusr1, 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, 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|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigusr2, s);
|
r = sd_event_add_signal(s->event, &s->sigusr2_event_source, SIGUSR2, 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|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigterm, s);
|
r = sd_event_add_signal(s->event, &s->sigterm_event_source, SIGTERM, dispatch_sigterm, s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1803,7 +1805,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|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigterm, s);
|
r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1814,7 +1816,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)|SD_EVENT_SIGNAL_PROCMASK, dispatch_sigrtmin1, s);
|
r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+1, dispatch_sigrtmin1, s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1822,7 +1824,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, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, &s->sigrtmin18_info);
|
r = sd_event_add_signal(s->event, NULL, SIGRTMIN+18, sigrtmin18_handler, &s->sigrtmin18_info);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -86,11 +86,15 @@ static int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_set_signal_exit(m->event, true);
|
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata= */ NULL);
|
r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, 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;
|
||||||
|
|
||||||
|
@ -822,7 +826,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 + 0 is used as global VT-release signal, SIGRTMIN + 1 is used
|
* SIGRTMIN 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.
|
||||||
|
@ -834,10 +838,11 @@ 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, /* ret_event_source= */ NULL, (SIGRTMIN + 0) | SD_EVENT_SIGNAL_PROCMASK, manager_vt_switch, m);
|
r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to subscribe to SIGRTMIN+0 signal: %m");
|
return log_error_errno(r, "Failed to subscribe to signal: %m");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1092,7 +1097,7 @@ static int manager_startup(Manager *m) {
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, SIGHUP|SD_EVENT_SIGNAL_PROCMASK, manager_dispatch_reload_signal, m);
|
r = sd_event_add_signal(m->event, NULL, SIGHUP, 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");
|
||||||
|
|
||||||
|
@ -1242,7 +1247,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, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGHUP, SIGTERM, SIGINT, SIGCHLD, SIGRTMIN+18) >= 0);
|
||||||
|
|
||||||
r = manager_new(&m);
|
r = manager_new(&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -1220,6 +1220,8 @@ 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.");
|
||||||
|
@ -1227,9 +1229,8 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_event_set_signal_exit(event, true);
|
(void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
|
||||||
if (r < 0)
|
(void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
||||||
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,11 +55,15 @@ static int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_set_signal_exit(m->event, true);
|
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata= */ NULL);
|
r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, 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;
|
||||||
|
|
||||||
|
@ -328,7 +332,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, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
|
||||||
|
|
||||||
r = manager_new(&m);
|
r = manager_new(&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -410,7 +410,8 @@ int manager_new(Manager **ret,
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
(void) sd_event_set_signal_exit(m->event, true);
|
(void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
||||||
|
(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,6 +204,8 @@ 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,10 +5601,6 @@ 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,7 +657,11 @@ int manager_new(Manager **ret) {
|
||||||
|
|
||||||
(void) sd_event_set_watchdog(m->event, true);
|
(void) sd_event_set_watchdog(m->event, true);
|
||||||
|
|
||||||
r = sd_event_set_signal_exit(m->event, true);
|
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
||||||
|
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,6 +167,8 @@ 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("Preparing to populate %s filesystem.", p->format);
|
log_info("Populating %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("Ready to populate %s filesystem.", p->format);
|
log_info("Successfully populated %s filesystem.", p->format);
|
||||||
|
|
||||||
*ret = TAKE_PTR(root);
|
*ret = TAKE_PTR(root);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -36,11 +36,15 @@ static int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_set_signal_exit(m->event, true);
|
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, /* ret_event_source= */ NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata= */ NULL);
|
r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, 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;
|
||||||
|
|
||||||
|
@ -138,7 +142,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, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 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;
|
||||||
|
|
||||||
r = sd_event_set_signal_exit(m->event, true);
|
(void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
||||||
if (r < 0)
|
(void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
||||||
return r;
|
(void) sd_event_add_signal(m->event, NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, manager_dispatch_reload_signal, m);
|
||||||
|
|
||||||
(void) sd_event_set_watchdog(m->event, true);
|
(void) sd_event_set_watchdog(m->event, true);
|
||||||
|
|
||||||
|
@ -720,25 +720,10 @@ int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
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->sigusr1_event_source, SIGUSR1, manager_sigusr1, m);
|
||||||
if (r < 0)
|
(void) sd_event_add_signal(m->event, &m->sigusr2_event_source, SIGUSR2, manager_sigusr2, m);
|
||||||
return log_debug_errno(r, "Failed install SIGHUP handler: %m");
|
(void) sd_event_add_signal(m->event, &m->sigrtmin1_event_source, SIGRTMIN+1, manager_sigrtmin1, 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);
|
||||||
|
|
||||||
|
@ -816,6 +801,10 @@ 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);
|
||||||
|
|
|
@ -123,6 +123,10 @@ 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,6 +67,8 @@ 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,6 +1875,8 @@ 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,7 +23,6 @@
|
||||||
#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] = {
|
||||||
|
@ -49,7 +48,6 @@ 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);
|
||||||
|
@ -531,18 +529,10 @@ static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = -strverscmp_improved(a->id_without_profile ?: a->id, b->id_without_profile ?: b->id);
|
r = -strverscmp_improved(a->id, 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;
|
||||||
|
|
||||||
|
@ -646,30 +636,28 @@ 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,
|
||||||
unsigned profile,
|
const char *osrelease,
|
||||||
const char *osrelease_text,
|
const char *cmdline,
|
||||||
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_text);
|
assert(osrelease);
|
||||||
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_text, strlen(osrelease_text), "r");
|
f = fmemopen_unlocked((void*) osrelease, strlen(osrelease), "r");
|
||||||
if (!f)
|
if (!f)
|
||||||
return log_oom();
|
return log_error_errno(errno, "Failed to open os-release buffer: %m");
|
||||||
|
|
||||||
r = parse_env_file(f, "os-release",
|
r = parse_env_file(f, "os-release",
|
||||||
"PRETTY_NAME", &os_pretty_name,
|
"PRETTY_NAME", &os_pretty_name,
|
||||||
|
@ -697,28 +685,10 @@ 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;
|
||||||
|
@ -726,19 +696,6 @@ 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)
|
||||||
|
@ -757,18 +714,13 @@ static int boot_entry_load_unified(
|
||||||
if (!tmp.kernel)
|
if (!tmp.kernel)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
tmp.options = strv_new(cmdline_text);
|
tmp.options = strv_new(skip_leading_chars(cmdline, WHITESPACE));
|
||||||
if (!tmp.options)
|
if (!tmp.options)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (profile_title)
|
delete_trailing_chars(tmp.options[0], WHITESPACE);
|
||||||
tmp.title = strjoin(good_name, " (", profile_title, ")");
|
|
||||||
else if (profile_id)
|
tmp.title = strdup(good_name);
|
||||||
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();
|
||||||
|
|
||||||
|
@ -788,7 +740,11 @@ static int boot_entry_load_unified(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pe_load_headers_and_sections(
|
/* Maximum PE section we are willing to load (Note that sections we are not interested in may be larger, but
|
||||||
|
* 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,
|
||||||
|
@ -818,177 +774,92 @@ static int pe_load_headers_and_sections(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const IMAGE_SECTION_HEADER* pe_find_profile_section_table(
|
static int find_cmdline_section(
|
||||||
const PeHeader *pe_header,
|
|
||||||
const IMAGE_SECTION_HEADER *sections,
|
|
||||||
unsigned profile,
|
|
||||||
size_t *ret_n_sections) {
|
|
||||||
|
|
||||||
assert(pe_header);
|
|
||||||
|
|
||||||
/* 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 (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;
|
|
||||||
|
|
||||||
const char *skipped = skip_leading_chars(*cmdline, WHITESPACE);
|
|
||||||
|
|
||||||
if (isempty(skipped)) {
|
|
||||||
*cmdline = mfree(*cmdline);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skipped != *cmdline) {
|
|
||||||
_cleanup_free_ char *c = strdup(skipped);
|
|
||||||
if (!c)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
free_and_replace(*cmdline, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete_trailing_chars(*cmdline, WHITESPACE);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Maximum PE section we are willing to load (Note that sections we are not interested in may be larger, but
|
|
||||||
* 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 pe_find_uki_sections(
|
|
||||||
int fd,
|
int fd,
|
||||||
const char *path,
|
const char *path,
|
||||||
unsigned profile,
|
IMAGE_SECTION_HEADER *sections,
|
||||||
char **ret_osrelease,
|
PeHeader *pe_header,
|
||||||
char **ret_profile,
|
char **ret_cmdline) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
char *cmdline = NULL, *t = NULL;
|
||||||
|
_cleanup_free_ char *word = NULL;
|
||||||
|
|
||||||
|
assert(path);
|
||||||
|
|
||||||
|
if (!ret_cmdline)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = pe_read_section_data(fd, pe_header, sections, ".cmdline", PE_SECTION_SIZE_MAX, (void**) &cmdline, NULL);
|
||||||
|
if (r == -ENXIO) { /* cmdline is optional */
|
||||||
|
*ret_cmdline = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return log_warning_errno(r, "Failed to read .cmdline section of '%s': %m", path);
|
||||||
|
|
||||||
|
word = strdup(cmdline);
|
||||||
|
if (!word)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
/* Quick test to check if there is actual content in the addon cmdline */
|
||||||
|
t = delete_chars(word, NULL);
|
||||||
|
if (isempty(t))
|
||||||
|
*ret_cmdline = NULL;
|
||||||
|
else
|
||||||
|
*ret_cmdline = TAKE_PTR(cmdline);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_osrel_section(
|
||||||
|
int fd,
|
||||||
|
const char *path,
|
||||||
|
IMAGE_SECTION_HEADER *sections,
|
||||||
|
PeHeader *pe_header,
|
||||||
|
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,
|
||||||
|
const char *path,
|
||||||
|
char **ret_osrelease,
|
||||||
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;
|
||||||
|
|
||||||
assert(fd >= 0);
|
r = find_sections(fd, path, §ions, &pe_header);
|
||||||
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);
|
||||||
|
|
||||||
if (!pe_is_native(pe_header)) /* Don't process non-native UKIs */
|
r = find_osrel_section(fd, path, sections, pe_header, ret_osrelease);
|
||||||
goto nothing;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
/* Find part of the section table for this profile */
|
r = find_cmdline_section(fd, path, sections, pe_header, ret_cmdline);
|
||||||
size_t n_psections = 0;
|
if (r < 0)
|
||||||
const IMAGE_SECTION_HEADER *psections = pe_find_profile_section_table(pe_header, sections, profile, &n_psections);
|
return r;
|
||||||
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 pe_find_addon_sections(
|
static int find_addon_sections(
|
||||||
int fd,
|
int fd,
|
||||||
const char *path,
|
const char *path,
|
||||||
char **ret_cmdline) {
|
char **ret_cmdline) {
|
||||||
|
@ -997,39 +868,19 @@ static int pe_find_addon_sections(
|
||||||
_cleanup_free_ PeHeader *pe_header = NULL;
|
_cleanup_free_ PeHeader *pe_header = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(fd >= 0);
|
r = find_sections(fd, path, §ions, &pe_header);
|
||||||
assert(path);
|
|
||||||
|
|
||||||
r = pe_load_headers_and_sections(fd, path, §ions, &pe_header);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!pe_is_addon(pe_header, sections))
|
r = find_cmdline_section(fd, path, sections, pe_header, ret_cmdline);
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Parse PE file '%s' is not an add-on.", path);
|
/* If addon cmdline is empty or contains just separators,
|
||||||
|
* 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);
|
||||||
|
|
||||||
/* Define early, before the gotos below */
|
return r;
|
||||||
_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(
|
||||||
|
@ -1108,7 +959,7 @@ static int boot_entries_find_unified_addons(
|
||||||
if (!j)
|
if (!j)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (pe_find_addon_sections(fd, j, &cmdline) <= 0)
|
if (find_addon_sections(fd, j, &cmdline) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
location = strdup(j);
|
location = strdup(j);
|
||||||
|
@ -1181,13 +1032,19 @@ 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;
|
||||||
|
|
||||||
_cleanup_close_ int fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOFOLLOW|O_NOCTTY);
|
if (!GREEDY_REALLOC0(config->entries, config->n_entries + 1))
|
||||||
|
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;
|
||||||
|
@ -1199,30 +1056,23 @@ 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;
|
||||||
|
|
||||||
_cleanup_free_ char *j = path_join(full, de->d_name);
|
j = path_join(full, de->d_name);
|
||||||
if (!j)
|
if (!j)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
for (unsigned p = 0; p < UNIFIED_PROFILES_MAX; p++) {
|
if (find_uki_sections(fd, j, &osrelease, &cmdline) < 0)
|
||||||
_cleanup_free_ char *osrelease = NULL, *profile = NULL, *cmdline = NULL;
|
continue;
|
||||||
|
|
||||||
r = pe_find_uki_sections(fd, j, p, &osrelease, &profile, &cmdline);
|
r = boot_entry_load_unified(root, j, osrelease, cmdline, config->entries + config->n_entries);
|
||||||
if (r == 0) /* this profile does not exist, we are done */
|
if (r < 0)
|
||||||
break;
|
continue;
|
||||||
if (r < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!GREEDY_REALLOC0(config->entries, config->n_entries + 2))
|
/* look for .efi.extra.d */
|
||||||
return log_oom();
|
r = boot_entries_find_unified_local_addons(config, dirfd(d), de->d_name, full, config->entries + config->n_entries);
|
||||||
|
if (r < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (boot_entry_load_unified(root, j, p, osrelease, profile, cmdline, config->entries + config->n_entries) < 0)
|
config->n_entries++;
|
||||||
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;
|
||||||
|
@ -1798,14 +1648,8 @@ int show_boot_entry(
|
||||||
|
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
|
||||||
if (e->id) {
|
if (e->id)
|
||||||
printf(" id: %s", e->id);
|
printf(" id: %s\n", 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;
|
||||||
|
|
||||||
|
@ -1829,7 +1673,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
|
||||||
putchar('\n');
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e->sort_key)
|
if (e->sort_key)
|
||||||
|
|
|
@ -38,7 +38,6 @@ 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;
|
||||||
|
@ -56,7 +55,6 @@ 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 *result = NULL;
|
_cleanup_free_ char *ret = NULL;
|
||||||
size_t n_result = 0, n_unescaped = 0;
|
size_t n = 0;
|
||||||
const char *p;
|
const char *p;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
int r;
|
int r;
|
||||||
|
@ -427,18 +427,17 @@ int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **re
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
n_unescaped += r + !first; /* Count unescaped length to make max length determination below */
|
|
||||||
|
|
||||||
if (ret) {
|
if (_ret) {
|
||||||
if (!GREEDY_REALLOC(result, n_result + !first + DNS_LABEL_ESCAPED_MAX))
|
if (!GREEDY_REALLOC(ret, n + !first + DNS_LABEL_ESCAPED_MAX))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = dns_label_escape(label, r, result + n_result + !first, DNS_LABEL_ESCAPED_MAX);
|
r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
result[n_result] = '.';
|
ret[n] = '.';
|
||||||
} else {
|
} else {
|
||||||
char escaped[DNS_LABEL_ESCAPED_MAX];
|
char escaped[DNS_LABEL_ESCAPED_MAX];
|
||||||
|
|
||||||
|
@ -447,34 +446,28 @@ int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **re
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
n_result += r + !first;
|
n += r + !first;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
if (n_unescaped == 0) {
|
if (n > DNS_HOSTNAME_MAX)
|
||||||
/* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
if (!GREEDY_REALLOC(result, 2)) /* Room for dot, and already pre-allocate space for the trailing NUL byte at the same time */
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
result[n_result++] = '.';
|
|
||||||
}
|
|
||||||
|
|
||||||
n_unescaped++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n_unescaped > DNS_HOSTNAME_MAX) /* Enforce max length check on unescaped length */
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (ret) {
|
if (_ret) {
|
||||||
/* Suffix with a NUL byte */
|
if (n == 0) {
|
||||||
if (!GREEDY_REALLOC(result, n_result + 1))
|
/* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
|
||||||
return -ENOMEM;
|
if (!GREEDY_REALLOC(ret, 2))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
result[n_result] = 0;
|
ret[n++] = '.';
|
||||||
*ret = TAKE_PTR(result);
|
} else {
|
||||||
|
if (!GREEDY_REALLOC(ret, n + 1))
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[n] = 0;
|
||||||
|
*_ret = TAKE_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -66,5 +66,9 @@ 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,19 +61,30 @@ int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_device_part_uuid(const char *variable, sd_id128_t *ret) {
|
int efi_loader_get_device_part_uuid(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;
|
||||||
|
|
||||||
return efi_get_variable_id128(variable, ret);
|
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderDevicePartUUID), &p);
|
||||||
}
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
int efi_loader_get_device_part_uuid(sd_id128_t *ret) {
|
if (sscanf(p, SD_ID128_UUID_FORMAT_STR,
|
||||||
return get_device_part_uuid(EFI_LOADER_VARIABLE(LoaderDevicePartUUID), ret);
|
&parsed[0], &parsed[1], &parsed[2], &parsed[3],
|
||||||
}
|
&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;
|
||||||
|
|
||||||
int efi_stub_get_device_part_uuid(sd_id128_t *ret) {
|
if (ret)
|
||||||
return get_device_part_uuid(EFI_LOADER_VARIABLE(StubDevicePartUUID), ret);
|
for (unsigned i = 0; i < ELEMENTSOF(parsed); i++)
|
||||||
|
ret->bytes[i] = parsed[i];
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int efi_loader_get_entries(char ***ret) {
|
int efi_loader_get_entries(char ***ret) {
|
||||||
|
@ -342,22 +353,6 @@ 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,7 +11,6 @@
|
||||||
#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);
|
||||||
|
@ -24,8 +23,6 @@ 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) {
|
||||||
|
@ -61,10 +58,6 @@ 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,7 +14,6 @@
|
||||||
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",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,7 +36,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_by_name(
|
r = pe_read_section_data(
|
||||||
fd,
|
fd,
|
||||||
pe_header,
|
pe_header,
|
||||||
sections,
|
sections,
|
||||||
|
@ -92,13 +91,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_by_name(fd, pe_header, sections, ".cmdline", PE_SECTION_READ_MAX, (void**) &cmdline, NULL);
|
r = pe_read_section_data(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_by_name(fd, pe_header, sections, ".uname", PE_SECTION_READ_MAX, (void**) &uname, NULL);
|
r = pe_read_section_data(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;
|
||||||
}
|
}
|
||||||
|
@ -160,16 +159,6 @@ 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,7 +8,6 @@
|
||||||
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,7 +6,6 @@
|
||||||
#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);
|
||||||
|
@ -38,21 +37,22 @@ 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_section_table_find(
|
const IMAGE_SECTION_HEADER *pe_header_find_section(
|
||||||
|
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 || n_sections == 0);
|
assert(sections || le16toh(pe_header->pe.NumberOfSections) == 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, n_sections)
|
FOREACH_ARRAY(section, sections, le16toh(pe_header->pe.NumberOfSections))
|
||||||
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,16 +60,6 @@ const IMAGE_SECTION_HEADER *pe_section_table_find(
|
||||||
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,
|
||||||
|
@ -183,28 +173,43 @@ int pe_load_sections(
|
||||||
|
|
||||||
int pe_read_section_data(
|
int pe_read_section_data(
|
||||||
int fd,
|
int fd,
|
||||||
const IMAGE_SECTION_HEADER *section,
|
const PeHeader *pe_header,
|
||||||
|
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) {
|
||||||
|
|
||||||
assert(fd >= 0);
|
const IMAGE_SECTION_HEADER *section;
|
||||||
assert(section);
|
_cleanup_free_ void *data = NULL;
|
||||||
|
size_t n;
|
||||||
|
ssize_t ss;
|
||||||
|
|
||||||
size_t n = le32toh(section->VirtualSize);
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
_cleanup_free_ void *data = malloc(n+1);
|
data = malloc(n+1);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ssize_t ss = pread(fd, data, n, le32toh(section->PointerToRawData));
|
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 {
|
||||||
|
@ -216,37 +221,12 @@ 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);
|
||||||
|
@ -260,27 +240,3 @@ 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,15 +135,10 @@ 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 IMAGE_SECTION_HEADER *section, size_t max_size, void **ret, size_t *ret_size);
|
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_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|SD_EVENT_SIGNAL_PROCMASK, on_sigwinch_event, f);
|
r = sd_event_add_signal(f->event, &f->sigwinch_event_source, SIGWINCH, on_sigwinch_event, f);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -375,9 +375,6 @@ 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,21 +1132,15 @@ int manager_new(Manager **ret) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_event_set_signal_exit(m->event, true);
|
(void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
||||||
if (r < 0)
|
(void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
||||||
return r;
|
(void) 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)
|
|
||||||
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");
|
||||||
|
|
||||||
r = sd_event_set_watchdog(m->event, true);
|
(void) 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,6 +179,8 @@ 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,13 +184,19 @@ 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_set_signal_exit(event, true);
|
r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to enable SIGTERM/SIGINT handling: %m");
|
return log_error_errno(r, "Failed to create sigterm event source: %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,8 +170,6 @@ typedef struct Item {
|
||||||
|
|
||||||
bool try_replace:1;
|
bool try_replace:1;
|
||||||
|
|
||||||
bool purge:1;
|
|
||||||
|
|
||||||
OperationMask done;
|
OperationMask done;
|
||||||
} Item;
|
} Item;
|
||||||
|
|
||||||
|
@ -3048,9 +3046,6 @@ 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))
|
||||||
|
@ -3607,7 +3602,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, purge = false;
|
unbase64 = false, from_cred = false, missing_user_or_group = false;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(fname);
|
assert(fname);
|
||||||
|
@ -3673,8 +3668,6 @@ 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),
|
||||||
|
@ -3691,7 +3684,6 @@ 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))
|
||||||
|
@ -3846,12 +3838,6 @@ 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,7 +11,6 @@ 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();
|
||||||
|
|
||||||
|
@ -19,7 +18,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, &is_case_sensitive);
|
r = udev_rule_parse_value(str, &value, &endpos);
|
||||||
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,16 +4,15 @@
|
||||||
#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, bool expected_case_insensitive, int expected_retval) {
|
static void test_udev_rule_parse_value_one(const char *in, const char *expected_value, 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, &i) == expected_retval);
|
assert_se(udev_rule_parse_value(str, &value, &endpos) == 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));
|
||||||
|
@ -26,7 +25,6 @@ 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,61 +33,45 @@ 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", /* case_insensitive = */ false, 0);
|
test_udev_rule_parse_value_one("\"valid operand\"", "valid operand", 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", /* case_insensitive = */ false, 0);
|
test_udev_rule_parse_value_one("\"va'l\\'id\\\"op\\\"erand\"", "va'l\\'id\"op\"erand", 0);
|
||||||
test_udev_rule_parse_value_one("no quotes", NULL, /* case_insensitive = */ false, -EINVAL);
|
test_udev_rule_parse_value_one("no quotes", NULL, -EINVAL);
|
||||||
test_udev_rule_parse_value_one("\"\\\\a\\b\\x\\y\"", "\\\\a\\b\\x\\y", /* case_insensitive = */ false, 0);
|
test_udev_rule_parse_value_one("\"\\\\a\\b\\x\\y\"", "\\\\a\\b\\x\\y", 0);
|
||||||
test_udev_rule_parse_value_one("\"reject\0nul\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
test_udev_rule_parse_value_one("\"reject\0nul\"", NULL, -EINVAL);
|
||||||
/* input: e"" */
|
/* input: e"" */
|
||||||
test_udev_rule_parse_value_one("e\"\"", "", /* case_insensitive = */ false, 0);
|
test_udev_rule_parse_value_one("e\"\"", "", 0);
|
||||||
/* input: e"1234" */
|
/* input: e"1234" */
|
||||||
test_udev_rule_parse_value_one("e\"1234\"", "1234", /* case_insensitive = */ false, 0);
|
test_udev_rule_parse_value_one("e\"1234\"", "1234", 0);
|
||||||
/* input: e"\"" */
|
/* input: e"\"" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\"\"", "\"", /* case_insensitive = */ false, 0);
|
test_udev_rule_parse_value_one("e\"\\\"\"", "\"", 0);
|
||||||
/* input: e"\ */
|
/* input: e"\ */
|
||||||
test_udev_rule_parse_value_one("e\"\\", NULL, /* case_insensitive = */ false, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\", NULL, -EINVAL);
|
||||||
/* input: e"\" */
|
/* input: e"\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\\"", NULL, -EINVAL);
|
||||||
/* input: e"\\" */
|
/* input: e"\\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\"", "\\", /* case_insensitive = */ false, 0);
|
test_udev_rule_parse_value_one("e\"\\\\\"", "\\", 0);
|
||||||
/* input: e"\\\" */
|
/* input: e"\\\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\\\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\\\\\\"", NULL, -EINVAL);
|
||||||
/* input: e"\\\"" */
|
/* input: e"\\\"" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\\\"\"", "\\\"", /* case_insensitive = */ false, 0);
|
test_udev_rule_parse_value_one("e\"\\\\\\\"\"", "\\\"", 0);
|
||||||
/* input: e"\\\\" */
|
/* input: e"\\\\" */
|
||||||
test_udev_rule_parse_value_one("e\"\\\\\\\\\"", "\\\\", /* case_insensitive = */ false, 0);
|
test_udev_rule_parse_value_one("e\"\\\\\\\\\"", "\\\\", 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", /* case_insensitive = */ false, 0);
|
test_udev_rule_parse_value_one("e\"operand with newline\\n\"", "operand with newline\n", 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", /* case_insensitive = */ false, 0);
|
"e\"single\\rcharacter\\t\\aescape\\bsequence\"", "single\rcharacter\t\aescape\bsequence", 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, /* case_insensitive = */ false, -EINVAL);
|
test_udev_rule_parse_value_one("e\"reject\\invalid escape sequence", NULL, -EINVAL);
|
||||||
/* input: e"\ */
|
/* input: e"\ */
|
||||||
test_udev_rule_parse_value_one("e\"\\", NULL, /* case_insensitive = */ false, -EINVAL);
|
test_udev_rule_parse_value_one("e\"\\", NULL, -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",
|
||||||
/* case_insensitive = */ false, 0);
|
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,6 +153,8 @@ 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);
|
||||||
|
@ -1350,13 +1352,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, /* ret_event_source= */ NULL, /* callback= */ NULL, /* userdata= */ NULL);
|
r = sd_event_add_memory_pressure(manager->event, &manager->memory_pressure_event_source, 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(manager->event, /* ret_event_source= */ NULL,
|
r = sd_event_add_signal(manager->event, &manager->memory_pressure_event_source,
|
||||||
(SIGRTMIN+18) | SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, /* userdata= */ NULL);
|
(SIGRTMIN+18) | SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, 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,6 +35,9 @@ 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,15 +63,9 @@ 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 $ */
|
||||||
|
@ -161,7 +155,8 @@ 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:8;
|
UdevRuleSubstituteType attr_subst_type:7;
|
||||||
|
bool attr_match_remove_trailing_whitespace:1;
|
||||||
const char *value;
|
const char *value;
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
|
@ -300,7 +295,6 @@ 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), \
|
||||||
|
@ -494,10 +488,12 @@ 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, bool is_case_insensitive) {
|
static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type, UdevRuleOperatorType op, char *value, void *data) {
|
||||||
_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);
|
||||||
|
@ -556,21 +552,16 @@ 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]))
|
||||||
match_type |= MATCH_REMOVE_TRAILING_WHITESPACE;
|
remove_trailing_whitespace = true;
|
||||||
|
|
||||||
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;
|
||||||
|
@ -582,6 +573,7 @@ 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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -629,7 +621,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, bool is_case_insensitive) {
|
static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, UdevRuleOperatorType op, char *value) {
|
||||||
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;
|
||||||
|
@ -637,39 +629,35 @@ 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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_ACTION, op, value, NULL);
|
||||||
} 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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_DEVPATH, op, value, NULL);
|
||||||
} 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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_KERNEL, op, value, NULL);
|
||||||
} 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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_DEVLINK, op, value, NULL);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_DEVLINK, op, value, NULL, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_DEVLINK, op, value, NULL);
|
||||||
} 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);
|
||||||
|
@ -689,9 +677,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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_NAME, op, value, NULL);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_NAME, op, value, NULL, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_NAME, op, value, NULL);
|
||||||
} 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);
|
||||||
|
@ -709,15 +697,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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_ENV, op, value, attr);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_ENV, op, value, attr, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_ENV, op, value, attr);
|
||||||
} 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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_CONST, op, value, attr);
|
||||||
} 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);
|
||||||
|
@ -729,9 +717,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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_TAG, op, value, NULL);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_TAG, op, value, NULL, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_TAG, op, value, NULL);
|
||||||
} 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);
|
||||||
|
@ -741,14 +729,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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_SUBSYSTEM, op, value, NULL);
|
||||||
} 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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_DRIVER, op, value, NULL);
|
||||||
} 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)
|
||||||
|
@ -762,9 +750,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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_ATTR, op, value, attr);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_ATTR, op, value, attr, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_ATTR, op, value, attr);
|
||||||
} 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)
|
||||||
|
@ -778,30 +766,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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_SYSCTL, op, value, attr);
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_SYSCTL, op, value, attr, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_SYSCTL, op, value, attr);
|
||||||
} 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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_KERNEL, op, value, NULL);
|
||||||
} 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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_SUBSYSTEM, op, value, NULL);
|
||||||
} 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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_DRIVER, op, value, NULL);
|
||||||
} 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)
|
||||||
|
@ -814,14 +802,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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_ATTR, op, value, attr);
|
||||||
} 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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_PARENTS_TAG, op, value, NULL);
|
||||||
} else if (streq(key, "TEST")) {
|
} else if (streq(key, "TEST")) {
|
||||||
mode_t mode = MODE_INVALID;
|
mode_t mode = MODE_INVALID;
|
||||||
|
|
||||||
|
@ -833,10 +821,8 @@ 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), is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_TEST, op, value, MODE_TO_PTR(mode));
|
||||||
} 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);
|
||||||
|
@ -845,10 +831,8 @@ 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, /* is_case_insensitive */ false);
|
r = rule_line_add_token(rule_line, TK_M_PROGRAM, op, value, NULL);
|
||||||
} 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);
|
||||||
|
@ -857,20 +841,18 @@ 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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_FILE, op, value, NULL);
|
||||||
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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
||||||
} else
|
} else
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_PROGRAM, op, value, NULL, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_PROGRAM, op, value, NULL);
|
||||||
} else if (streq(attr, "builtin")) {
|
} else if (streq(attr, "builtin")) {
|
||||||
UdevBuiltinCommand cmd;
|
UdevBuiltinCommand cmd;
|
||||||
|
|
||||||
|
@ -878,13 +860,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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
||||||
} else if (streq(attr, "db"))
|
} else if (streq(attr, "db"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_DB, op, value, NULL, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_DB, op, value, NULL);
|
||||||
else if (streq(attr, "cmdline"))
|
else if (streq(attr, "cmdline"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_CMDLINE, op, value, NULL, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_CMDLINE, op, value, NULL);
|
||||||
else if (streq(attr, "parent"))
|
else if (streq(attr, "parent"))
|
||||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_PARENT, op, value, NULL, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_M_IMPORT_PARENT, op, value, NULL);
|
||||||
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")) {
|
||||||
|
@ -893,7 +875,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, is_case_insensitive);
|
r = rule_line_add_token(rule_line, TK_M_RESULT, op, value, NULL);
|
||||||
} else if (streq(key, "OPTIONS")) {
|
} else if (streq(key, "OPTIONS")) {
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
|
@ -905,24 +887,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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_NONE, op, NULL, NULL);
|
||||||
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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_REPLACE, op, NULL, NULL);
|
||||||
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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DB_PERSIST, op, NULL, NULL);
|
||||||
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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(1));
|
||||||
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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(0));
|
||||||
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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STATIC_NODE, op, tmp, NULL);
|
||||||
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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DEVLINK_PRIORITY, op, NULL, INT_TO_PTR(prio));
|
||||||
} else if ((tmp = startswith(value, "log_level="))) {
|
} else if ((tmp = startswith(value, "log_level="))) {
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
|
@ -933,7 +915,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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OPTIONS_LOG_LEVEL, op, NULL, INT_TO_PTR(level));
|
||||||
} 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;
|
||||||
|
@ -951,17 +933,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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid));
|
||||||
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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid));
|
||||||
} 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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_OWNER, op, value, NULL);
|
||||||
} 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;
|
||||||
|
@ -979,17 +961,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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid));
|
||||||
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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid));
|
||||||
} 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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_GROUP, op, value, NULL);
|
||||||
} 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;
|
||||||
|
@ -1007,10 +989,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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_MODE_ID, op, NULL, MODE_TO_PTR(mode));
|
||||||
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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_MODE, op, value, NULL);
|
||||||
}
|
}
|
||||||
} else if (streq(key, "SECLABEL")) {
|
} else if (streq(key, "SECLABEL")) {
|
||||||
if (isempty(attr))
|
if (isempty(attr))
|
||||||
|
@ -1023,13 +1005,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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_SECLABEL, op, value, attr);
|
||||||
} 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, /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_RUN_PROGRAM, op, value, NULL);
|
||||||
else if (streq(attr, "builtin")) {
|
else if (streq(attr, "builtin")) {
|
||||||
UdevBuiltinCommand cmd;
|
UdevBuiltinCommand cmd;
|
||||||
|
|
||||||
|
@ -1037,7 +1019,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), /* is_case_insensitive = */ false);
|
r = rule_line_add_token(rule_line, TK_A_RUN_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
||||||
} 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")) {
|
||||||
|
@ -1137,30 +1119,13 @@ static void check_token_delimiters(UdevRuleLine *rule_line, const char *line) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos, bool *ret_is_case_insensitive) {
|
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
|
||||||
char *i, *j;
|
char *i, *j;
|
||||||
bool is_escaped = false, is_case_insensitive = false;
|
bool is_escaped;
|
||||||
|
|
||||||
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 */
|
||||||
str += is_escaped + is_case_insensitive;
|
is_escaped = str[0] == 'e';
|
||||||
|
str += is_escaped;
|
||||||
if (str[0] != '"')
|
if (str[0] != '"')
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -1207,11 +1172,10 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos, bool *
|
||||||
|
|
||||||
*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, bool *ret_is_case_insensitive) {
|
static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOperatorType *ret_op, char **ret_value) {
|
||||||
char *key_begin, *key_end, *attr, *tmp;
|
char *key_begin, *key_end, *attr, *tmp;
|
||||||
UdevRuleOperatorType op;
|
UdevRuleOperatorType op;
|
||||||
int r;
|
int r;
|
||||||
|
@ -1221,7 +1185,6 @@ 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 ",");
|
||||||
|
|
||||||
|
@ -1256,7 +1219,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, ret_is_case_insensitive);
|
r = udev_rule_parse_value(tmp, ret_value, line);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1328,18 +1291,17 @@ 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, &is_case_insensitive);
|
r = parse_line(&p, &key, &attr, &op, &value);
|
||||||
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, is_case_insensitive);
|
r = parse_token(rule_line, key, attr, op, value);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1450,6 +1412,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
@ -1464,6 +1427,7 @@ 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;
|
||||||
|
|
||||||
|
@ -1732,7 +1696,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, case_insensitive;
|
bool match = false;
|
||||||
|
|
||||||
assert(token);
|
assert(token);
|
||||||
assert(token->value);
|
assert(token->value);
|
||||||
|
@ -1740,17 +1704,13 @@ 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 & _MATCH_TYPE_MASK) {
|
switch (token->match_type) {
|
||||||
case MATCH_TYPE_EMPTY:
|
case MATCH_TYPE_EMPTY:
|
||||||
match = isempty(str);
|
match = isempty(str);
|
||||||
break;
|
break;
|
||||||
case MATCH_TYPE_SUBSYSTEM:
|
case MATCH_TYPE_SUBSYSTEM:
|
||||||
if (case_insensitive)
|
match = STR_IN_SET(str, "subsystem", "class", "bus");
|
||||||
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)) {
|
||||||
|
@ -1760,7 +1720,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 (case_insensitive ? strcaseeq(i, str) : streq(i, str)) {
|
if (streq(i, str)) {
|
||||||
match = true;
|
match = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1773,7 +1733,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, case_insensitive ? FNM_CASEFOLD : 0) == 0)) {
|
if ((fnmatch(i, str, 0) == 0)) {
|
||||||
match = true;
|
match = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1813,7 +1773,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 (FLAGS_SET(token->match_type, MATCH_REMOVE_TRAILING_WHITESPACE)) {
|
if (token->attr_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);
|
||||||
}
|
}
|
||||||
|
@ -1825,7 +1785,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 (FLAGS_SET(token->match_type, MATCH_REMOVE_TRAILING_WHITESPACE))
|
if (token->attr_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, bool *ret_is_case_insensitive);
|
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos);
|
||||||
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,11 +208,9 @@ int monitor_main(int argc, char *argv[], void *userdata) {
|
||||||
goto finalize;
|
goto finalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_event_set_signal_exit(event, true);
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
|
||||||
if (r < 0) {
|
(void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
||||||
log_error_errno(r, "Failed to install SIGINT/SIGTERM handling: %m");
|
(void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
|
||||||
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, /* ret_old_mask=*/ NULL, SIGCHLD) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, /* old_sigset=*/ NULL, SIGCHLD, SIGWINCH) >= 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,17 +2313,6 @@ 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,8 +237,6 @@ 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.'
|
||||||
|
@ -277,12 +275,10 @@ 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,39 +9,26 @@ 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
|
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
#!/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
|
|
|
@ -1,240 +0,0 @@
|
||||||
#!/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,9 +5,6 @@
|
||||||
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
|
||||||
|
|
||||||
|
@ -21,14 +18,9 @@ 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
|
||||||
|
|
||||||
|
@ -41,11 +33,6 @@ 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'
|
||||||
|
@ -53,6 +40,373 @@ 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
|
||||||
|
@ -63,8 +417,4 @@ 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
|
||||||
|
|
|
@ -427,15 +427,14 @@ systemctl is-active testservice-50e.service
|
||||||
# Check vpick support in ExtensionImages=
|
# Check vpick support in ExtensionImages=
|
||||||
VBASE="vtest$RANDOM"
|
VBASE="vtest$RANDOM"
|
||||||
VDIR="/tmp/$VBASE.v"
|
VDIR="/tmp/$VBASE.v"
|
||||||
EMPTY_VDIR="/tmp/$VBASE-empty.v"
|
mkdir "$VDIR"
|
||||||
mkdir "$VDIR" "$EMPTY_VDIR"
|
|
||||||
|
|
||||||
ln -s /tmp/app0.raw "$VDIR/${VBASE}_0.raw"
|
ln -s /tmp/app0.raw "$VDIR/${VBASE}_0.raw"
|
||||||
ln -s /tmp/app1.raw "$VDIR/${VBASE}_1.raw"
|
ln -s /tmp/app1.raw "$VDIR/${VBASE}_1.raw"
|
||||||
|
|
||||||
systemd-run -P -p ExtensionImages="$VDIR -$EMPTY_VDIR" bash -c '/opt/script1.sh | grep ID'
|
systemd-run -P -p ExtensionImages="$VDIR" bash -c '/opt/script1.sh | grep ID'
|
||||||
|
|
||||||
rm -rf "$VDIR" "$EMPTY_VDIR"
|
rm -rf "$VDIR"
|
||||||
|
|
||||||
# ExtensionDirectories will set up an overlay
|
# ExtensionDirectories will set up an overlay
|
||||||
mkdir -p "$IMAGE_DIR/app0" "$IMAGE_DIR/app1" "$IMAGE_DIR/app-nodistro" "$IMAGE_DIR/service-scoped-test"
|
mkdir -p "$IMAGE_DIR/app0" "$IMAGE_DIR/app1" "$IMAGE_DIR/app-nodistro" "$IMAGE_DIR/service-scoped-test"
|
||||||
|
@ -503,15 +502,14 @@ systemctl is-active testservice-50f.service
|
||||||
# Check vpick support in ExtensionDirectories=
|
# Check vpick support in ExtensionDirectories=
|
||||||
VBASE="vtest$RANDOM"
|
VBASE="vtest$RANDOM"
|
||||||
VDIR="/tmp/$VBASE.v"
|
VDIR="/tmp/$VBASE.v"
|
||||||
EMPTY_VDIR="/tmp/$VBASE-empty.v"
|
mkdir "$VDIR"
|
||||||
mkdir "$VDIR" "$EMPTY_VDIR"
|
|
||||||
|
|
||||||
ln -s "$IMAGE_DIR/app0" "$VDIR/${VBASE}_0"
|
ln -s "$IMAGE_DIR/app0" "$VDIR/${VBASE}_0"
|
||||||
ln -s "$IMAGE_DIR/app1" "$VDIR/${VBASE}_1"
|
ln -s "$IMAGE_DIR/app1" "$VDIR/${VBASE}_1"
|
||||||
|
|
||||||
systemd-run -P --property ExtensionDirectories="$VDIR -$EMPTY_VDIR" cat /opt/script1.sh | grep -q -F "extension-release.app2"
|
systemd-run -P --property ExtensionDirectories="$VDIR" cat /opt/script1.sh | grep -q -F "extension-release.app2"
|
||||||
|
|
||||||
rm -rf "$VDIR" "$EMPTY_VDIR"
|
rm -rf "$VDIR"
|
||||||
|
|
||||||
systemd-dissect --umount "$IMAGE_DIR/app0"
|
systemd-dissect --umount "$IMAGE_DIR/app0"
|
||||||
systemd-dissect --umount "$IMAGE_DIR/app1"
|
systemd-dissect --umount "$IMAGE_DIR/app1"
|
||||||
|
|
|
@ -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