1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-18 10:04:04 +03:00

Compare commits

...

74 Commits

Author SHA1 Message Date
Lennart Poettering
8cbcdc78db update TODO 2024-12-20 17:52:09 +01:00
Lennart Poettering
4103bf9f2f man: document the new per-use credstore paths
(And some other minor tweaks)
2024-12-20 17:52:07 +01:00
Lennart Poettering
026dfd60d4 test: add integration test that makes sure unpriv creds work correctly
This checks both the per-user credstore directory logic, and that
unprivileged, encrypted credentials work.
2024-12-20 17:52:04 +01:00
Lennart Poettering
1af989e8de pid1: add support for decrypting per-user credentials
When I added support for unprivileged credentials I apparently never
hooked them up to service management correctly. Let's fix that.

Fixes: #33796 #33318
2024-12-20 17:52:01 +01:00
Lennart Poettering
8506a9955c execute: introduce a user-scoped credstore
Fixes: #33887
2024-12-20 17:51:58 +01:00
Lennart Poettering
d2cd189324 sd-path: expose credential store in sd-path 2024-12-20 17:51:54 +01:00
Lennart Poettering
b226b7fb6d systemd-path: add the usual ANSI sequences to --help text 2024-12-20 17:51:52 +01:00
Lennart Poettering
060e2512cd systemd-path: guarantee that tool exit status is zero on success
Let's not inherit the error code from an earlier function invocation.
2024-12-20 17:51:50 +01:00
Lennart Poettering
81082f2dc2 systemd-path: order all listed paths by their ID alphabetically
Let's add some system to the madness, given we added user-specific dirs
to the end of the list, but they should really be listed together with
the other user-specific ones.
2024-12-20 17:51:48 +01:00
Lennart Poettering
616586b910 sd-path: don't chop off trailing slash in sd_path apis, when user provided them
This is a minor compat break, but given the slow adoption of the
sd-path.h APIs I think it's one we should take. Basically, the idea is
that if the user provides a suffix path with a trailing slash (thus
encoding in the path that the last element must be a dir), we should
keep it in place, and not suppress it, in order to not willy nilly
reduce the amount of information contained in the path.

Simplifications that do not alter meaning, and do not suppress
information should be fine to apply to a path, but otherwise we really
should be conservative on this.
2024-12-20 17:51:46 +01:00
Lennart Poettering
cf7d0a2d2e pid1: normalize oom error handling a bit 2024-12-20 17:51:42 +01:00
Ricky Tigg
06ffa66a5b po: Translated using Weblate (Finnish)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Ricky Tigg <ricky.tigg@gmail.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/fi/
Translation: systemd/main
2024-12-21 00:51:18 +09:00
Septatrix
33bfa69b2e Add .venv to gitignore
This directory is commonly used for virtual Python environments.
These are useful when developing to install different Python versions
as well as install tooling like mkosi and mypy in an isolated fashion
without influencing the global system.
2024-12-20 15:33:32 +00:00
Lennart Poettering
f108996319
core/device: handle ID_PROCESSING udev property (#35351)
Continuation of #35332.
2024-12-20 10:12:39 +01:00
Daan De Meyer
dec47e58a6
debug-generator: add a kernel cmdline option to pause the boot process (#35410)
Introduce the `systemd.break=` kernel command line option to allow
stopping the boot process at a certain point and spawn a debug shell.
After exiting this shell, the system will resume booting.

It accepts the following values:
- `pre-udev`: before starting to process kernel uevents (initrd and
host).
- `pre-basic`: before leaving early boot and regular services start
(initrd and host).
- `pre-mount`: before the root filesystem is mounted (initrd).
- `pre-switch-root`: before switching root (initrd).
2024-12-20 10:04:41 +01:00
Lennart Poettering
cdcb1eeeb8
[RFC] better naming for Azure MANA network devices (#34255)
The Azure MANA folks would like the PCI domain to be suppressed from
naming network interfaces. Let's introduce a somewhat generic way to do
this, without hardcoding anything to Azure.

Specifically: we'll ship a new hwdb entry that sets a new
ID_NET_NAME_INCLUDE_DOMAIN=0 property on relevant MANA devices. Then we
make net_id look for that property, and if it is set we simply suppress
the PCI domain.

(Untested as of now, needs feedback from Azure MANA folks that this
actually works and does what is requested here).
2024-12-20 09:52:40 +01:00
Matteo Croce
77d4a263c1 mkosi: move config options
Move some config option in the right section, fixes the following warning:
```
mkosi.conf: Setting Credentials should be configured in [Runtime], not [Host].
mkosi.conf: Setting RuntimeBuildSources should be configured in [Runtime], not [Host].
mkosi.conf: Setting RuntimeScratch should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuSmp should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuSwtpm should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuVsock should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuKvm should be configured in [Runtime], not [Host].
```
2024-12-20 09:38:11 +01:00
Yu Watanabe
5f29c86ace audit-util: rename output parameter
To make them consistent with in audit-util.c.

Follow-up for 7e02ee98d86702b8e7055f0a6d8e6ea48267ad23.
2024-12-20 09:37:25 +01:00
Yu Watanabe
182ffb5819 TEST-71-HOSTNAME: do not start user session
The user session may trigger hostnamed, and the job of stopping
hostnamed may be cancelled, and the test may fail:
```
[ 4633.613578] TEST-71-HOSTNAME.sh[175]: + stop_hostnamed
[ 4633.613578] TEST-71-HOSTNAME.sh[175]: + systemctl stop systemd-hostnamed.service
[ 4633.664670] systemd[1]: Stopping systemd-hostnamed.service - Hostname Service...
[ 4636.022277] systemd-logind[121]: New session c2 of user root.
[ 4636.032532] systemd[1]: Created slice user-0.slice - User Slice of UID 0.
[ 4636.042675] systemd[1]: Starting user-runtime-dir@0.service - User Runtime Directory /run/user/0...
[ 4636.176140] systemd[1]: Finished user-runtime-dir@0.service - User Runtime Directory /run/user/0.
[ 4636.202951] systemd[1]: Starting user@0.service - User Manager for UID 0...
[ 4636.292204] systemd-logind[121]: New session c3 of user root.
[ 4636.300065] (systemd)[268]: pam_unix(systemd-user:session): session opened for user root(uid=0) by root(uid=0)
[ 4636.757667] systemd[268]: Queued start job for default target default.target.
[ 4636.774419] systemd[268]: Created slice app.slice - User Application Slice.
[ 4636.774579] systemd[268]: Started systemd-tmpfiles-clean.timer - Daily Cleanup of User's Temporary Directories.
[ 4636.774747] systemd[268]: Reached target paths.target - Paths.
[ 4636.776418] systemd[268]: Reached target sysinit.target - System Initialization.
[ 4636.776604] systemd[268]: Reached target timers.target - Timers.
[ 4636.784997] systemd[268]: Starting dbus.socket - D-Bus User Message Bus Socket...
[ 4636.799472] systemd[268]: Starting systemd-tmpfiles-setup.service - Create User Files and Directories...
[ 4637.027125] systemd[268]: Finished systemd-tmpfiles-setup.service - Create User Files and Directories.
[ 4637.031721] systemd[268]: Listening on dbus.socket - D-Bus User Message Bus Socket.
[ 4637.036189] systemd[268]: Reached target sockets.target - Sockets.
[ 4637.036373] systemd[268]: Reached target basic.target - Basic System.
[ 4637.036558] systemd[268]: Reached target default.target - Main User Target.
[ 4637.036646] systemd[268]: Startup finished in 702ms.
[ 4637.049075] systemd[1]: Started user@0.service - User Manager for UID 0.
[ 4637.075263] systemd[1]: Started session-c2.scope - Session c2 of User root.
[ 4637.084917] login[136]: pam_unix(login:session): session opened for user root(uid=0) by root(uid=0)
[ 4637.117348] login[136]: ROOT LOGIN ON pts/0
[ 4637.238572] systemctl[261]: Job for systemd-hostnamed.service canceled.
[ 4637.290369] systemd[1]: TEST-71-HOSTNAME.service: Main process exited, code=exited, status=1/FAILURE
```

Fixes #35643.
2024-12-20 09:36:51 +01:00
Antonio Alvarez Feijoo
e9f781a5a4
debug-generator: add a kernel cmdline option to pause the boot process
Introduce the `systemd.break=` kernel command line option to allow stopping the
boot process at a certain point and spawn a debug shell. After exiting this
shell, the system will resume booting.

It accepts the following values:
- `pre-udev`: before starting to process kernel uevents (initrd and host).
- `pre-basic`: before leaving early boot and regular services start (initrd and
host).
- `pre-mount`: before the root filesystem is mounted (initrd).
- `pre-switch-root`: before switching root (initrd).
2024-12-20 08:51:23 +01:00
Antonio Alvarez Feijoo
cb3801a4c9
man/debug-generator: add a section for kernel command line options 2024-12-20 08:48:23 +01:00
Yu Watanabe
8a135111ca
capability-util: generalize helper to acquire local caps (#35403)
This generalizes and modernizes the code to acquire set of local caps,
based on the code for this in the condition logic. Uses PidRef, and
acquires the full quintuplet of caps.

This can be considered preparation to one day maybe build without
libcap.
2024-12-20 11:52:24 +09:00
Yu Watanabe
5e837858e7
analyze: add "chid" verb to display CHIDs of the local system (#35175)
We already have the code for it, expose it in systemd-analyze, because
it's useful.
2024-12-20 11:47:03 +09:00
Yu Watanabe
a3fecea5e2
Small fixes to nspawn and other stuff (#35686)
Split out ouf #35685.
2024-12-20 11:03:59 +09:00
Yu Watanabe
f01132aacf TEST-17: add test case for ID_PROCESSING flag on add uevent
Also, check the state of the device units on change event.
2024-12-20 10:52:57 +09:00
Yu Watanabe
ad920b4cb3 core/device: handle ID_PROCESSING udev property
If an enumerated device has ID_PROCESSING=1 property, and the service
manager does not know if the device has been processed by udevd
previously (that is, Device.deserialized_found does not have
DEVICE_FOUND_UDEV), then drop DEVICE_FOUND_UDEV flag from the device and
make the device not enter the active state.

Follow-up for 405be62f05d76f1845f347737b5972158c79dd3e, which was
reverted by c4fc22c4defc5983e53f4ce048e15ea7d31e6a75.
2024-12-20 10:52:57 +09:00
Yu Watanabe
a7396f8364 core/device: use path_equal() to compare sysfs path
The hashmap Manager.devices_by_sysfs uses path_hash_ops.
Let's consistent compare function.
2024-12-20 10:52:57 +09:00
Yu Watanabe
71ec342d13 core/device: rename output parameters of device_setup_units() to ret_xyz
No functional change, just refactoring.
2024-12-20 10:52:57 +09:00
Yu Watanabe
3b9010b170
udev: support reloading udev.conf (#35458)
This makes systemd-udevd reload udev.conf when explicitly requested by
e.g. `udevadm control --reload`.
2024-12-20 09:00:48 +09:00
Yu Watanabe
cf89e48028 ptyfwd: reset writable/readable flag before shovel() on exit
Follow-up for 12807b5a49d1fe60434d473afe11ff81a4c92306.

Otherwise, if a call of shovel() disabled the flags, the subsequent
calls do nothing even if there is something we need to read or write.

Fixes the following error:
```
Dec 19 02:19:39 run0[5618]: Error on PTY forwarding logic: Too many levels of symbolic links
```
2024-12-20 08:59:41 +09:00
Ivan Kruglov
3cbf00a30c machine: make TEST-13-NSPAWN wqlong-running code more verbose
Need this to debug https://github.com/systemd/systemd/issues/35115
2024-12-19 17:09:04 +00:00
Luca Boccassi
0f67cb3606
Minor fixes in man pages, example scripts, error log (#35683)
No functional changes.
2024-12-19 17:08:13 +00:00
Lennart Poettering
5ceb38cb1e nspawn: switch to read_virtual_file() for reading audit loginuid 2024-12-19 15:37:00 +01:00
Lennart Poettering
312cf91005 nsresource: print nicer error message when trying to acquire an unpriv user ns range where this isn't possible 2024-12-19 15:35:23 +01:00
Lennart Poettering
b1b128d0e2 mount-util: add debug message to make_userns() failure 2024-12-19 15:33:52 +01:00
Lennart Poettering
91cdc8ab0f mount-util: add debug output when we switched root 2024-12-19 15:33:44 +01:00
Lennart Poettering
009a02b263 nspawn: trivial improvements 2024-12-19 15:33:34 +01:00
Lennart Poettering
b83358b87f nspawn: rename pin_fully_visible_fs() → pin_fully_visible_api_fs()
This function pins the *API* FS, i.e. /proc/ + /sys/, not just any fs.
Hence clarify this in the name.

(At least we call these two fs "API (V)FS" in our codebase, hence
continue to do so here)
2024-12-19 15:33:24 +01:00
Lennart Poettering
bf1ef54d30 nspawn: add some additional useful debug logging 2024-12-19 15:33:10 +01:00
Lennart Poettering
8f9ea89ce4 nspawn: make unexpected mkdir() failures fatal
THis is just to make things easier to debug.
2024-12-19 15:33:06 +01:00
Lennart Poettering
5229cd839a nspawn: rename 'fd' variable to something more descriptive 2024-12-19 15:32:50 +01:00
Lennart Poettering
595ca10f37 nspawn: use DEVNUM_FORMAT_STR/DEVNUM_FORMAT_VAL more 2024-12-19 15:32:05 +01:00
Matthias Lisin
6e3f32cc56
man/sysupdate.features: fix typos 2024-12-19 12:39:32 +01:00
Matthias Lisin
1462736c7e
sysupdate: fix args order of formatted error 2024-12-19 12:39:31 +01:00
Matthias Lisin
f441831c9e
man/sysupdate.d: fix wrong PathRelativeTo value 2024-12-19 12:39:31 +01:00
Matthias Lisin
4bc06da775
man: fix args order for udevadm info cmd 2024-12-19 12:39:31 +01:00
Yu Watanabe
ced0ef3b35 TEST-17: use 'udevadm control --reload' or 'systemctl reload systemd-udevd.service' for reloading udev.conf
These should be equivalent. For coverage, one subtest uses systemctl and
another uses udevadm.
2024-12-19 19:00:38 +09:00
Yu Watanabe
e95861d909 udev: also reload udev.conf when explicitly requested
When reloading is explicitly requested, e.g. by 'udevadm control --reload',
then also reload udev.conf.
2024-12-19 18:57:32 +09:00
Yu Watanabe
0f72af536f udev: reload .rules files and builtins only when necessary
Previously, even if e.g. .rules files are unchanged, all .rules files
are reloaded when other kind of config files like .link files or
.hwdb.bin are changed, vice versa.
2024-12-19 18:55:18 +09:00
Yu Watanabe
b5ea69f5ac
udev: move config parsers and related things to udev-config.c (#35624)
No functional change, just refactoring and preparation for later
changes.
2024-12-19 18:41:52 +09:00
Yu Watanabe
04fa5c1580 udev-config: introduce UdevConfig
Then, save configurations by their source: udev.conf, command line
arguments, kernel command line options, and udev control.

Preparation to support reloading udev.conf in a later commit.
2024-12-19 12:28:44 +09:00
Yu Watanabe
394a678aec udev: move parsers for config file, kerenel command line, and positional arguments to udev-config.c
No functional change, just refactoring and preparation for later
commits.
2024-12-19 12:28:44 +09:00
Thomas Hebb
32c3e1379d ukify: Fix regression in --no-sign-kernel flag
The man page says that --sign-kernel and --no-sign-kernel "override the
detection of whether to sign the Linux binary", so we should only
autodetect if neither are specified. But as of commit 02eabaffe98c
("ukify: Add a unified interface for signing tools"), we autodetect even
when --no-sign-kernel is passed, which makes the flag useless.

The sign_kernel option is parsed using argparse.BooleanOptionalAction,
which sets it to either True, False, or None. commit 02eabaffe98c
replaced `sign_kernel is None` with `not sign_kernel`. These are not the
same in Python, as the latter accepts False as well as None.

Restore the original check and fix type annotations accordingly.

Fixes: 02eabaffe98c ("ukify: Add a unified interface for signing tools")
2024-12-19 12:27:27 +09:00
Lennart Poettering
0d1ebcf67d
networkd-sysctl: tweak error handling and log level a bit (#35673) 2024-12-18 18:20:30 +01:00
Lennart Poettering
0e5a83f510 analyze: drop conditioning of --no-legend and --json= on specific verbs
First of all, the list of verbs was badly out of date, in particular for
--no-legend. But second if it, I think such minor switches that alter
some detail of the output should not result in failure when the specific
tweak does not apply on some command. It should be fine for scripts and
suchlike to dumbly always pass --no-legend to all invocations of our
tools without having to consider if a specific subtool of ours actually
supports it or not.
2024-12-18 17:39:22 +01:00
Lennart Poettering
8f114904fc analyze: add verb for showing system's CHIDs
We have the code already, expose it in systemd-analyze too.

This should make it easier to debug the CHID use in the UKIs with
onboard tooling.
2024-12-18 17:38:42 +01:00
Mike Yuan
cffae6e113
networkd-sysctl: tweak error handling and log level a bit
Follow-up for 6d9ef22acdeac4b429efb75164341233955484af

- Downgrade log level for bpf not installed or kernel version
  being too old to LOG_DEBUG. Otherwise, on kernels older than 6.12
  the log becomes quite annoying.
- Always propagate the error and ignore only on caller's side.
  The current style is a messy mix.
2024-12-18 16:38:54 +01:00
Daan De Meyer
a48803fd84 man: Document generator sandbox environment 2024-12-19 00:36:52 +09:00
Mike Yuan
22583a002e
networkd-sysctl: rename functions to match our typical prefixes 2024-12-18 16:36:24 +01:00
Yu Watanabe
be1bcb85ce
ptyfwd: several cleanups (#35663) 2024-12-19 00:35:42 +09:00
Yu Watanabe
85d040dabd update-utmp: do not give up if the first attempt at connecting bus failed
Otherwise, the program exits with failure if the first attempt in run() failed:
```
Dec 18 20:27:37 systemd-update-utmp[254]: Bus n/a: changing state UNSET → OPENING
Dec 18 20:27:37 systemd-update-utmp[254]: sd-bus: starting bus by connecting to /run/systemd/private...
Dec 18 20:27:37 systemd-update-utmp[254]: Bus n/a: changing state OPENING → CLOSED
Dec 18 20:27:37 systemd-update-utmp[254]: Failed to get D-Bus connection: Connection refused
```
2024-12-19 00:34:38 +09:00
Yu Watanabe
67e5622bfe TEST-50-DISSECT: notify message cannot be sent by ncat
Follow-up for d0a63cf0412ccb9b4edd1f6048e25aa7f68b0133.

The command ncat may be already dead when the service manager receives
the notify message. Hence, the service cannot be found by the sender PID,
and the notify message will be ignored.
```
Dec 17 03:26:49 systemd[1]: Cannot find unit for notify message of PID 1159, ignoring.
Dec 17 03:26:49 systemd[1]: Received SIGCHLD from PID 1152 (bash).
Dec 17 03:26:49 systemd[1]: Child 1152 (bash) died (code=exited, status=0/SUCCESS)
Dec 17 03:26:49 systemd[1]: run-p1151-i1451.service: Child 1152 belongs to run-p1151-i1451.service.
Dec 17 03:26:49 systemd[1]: run-p1151-i1451.service: Main process exited, code=exited, status=0/SUCCESS (success)
Dec 17 03:26:49 systemd[1]: run-p1151-i1451.service: Failed with result 'protocol'.
Dec 17 03:26:49 systemd[1]: run-p1151-i1451.service: Service will not restart (restart setting)
Dec 17 03:26:49 systemd[1]: run-p1151-i1451.service: Changed start -> failed
```

This also drops unnecessary --pipe option and redundant check by 'env' command.
2024-12-18 15:50:02 +01:00
Morten Hauke Solvang
0da73fab56 resolved: if one transaction completes, expect other transactions within candidate to succeed quickly
Fixes #22575, as suggested by poettering in #35514.

Intended as a workaround for some buggy routers, which refuse to send empty
replies. If systemd-resolved starts two DnsTransactions, one for A and one
for AAAA, and the domain in question has no AAAA entry, then the server will
send a reply for A and no reply for AAAA. Correct behavior for the server would
be to send an empty reply for AAAA.

systemd-resolved would previously keep retrying the AAAA transaction, and
eventually timeout the whole query, returning an error to the caller.

Now, if the server replies to one query and not another, we cut short the
timeout and return the partial result. Returning the partial result allows
the rest of the system to keep working. It matches how e.g. glibc libnss_dns
behaves.
2024-12-18 15:43:46 +01:00
Yu Watanabe
64b504bde3 machinectl: explicitly assign PTY forwarder to sd_bus_slot
No functional change, just refactoring.
2024-12-18 20:28:28 +09:00
Yu Watanabe
12807b5a49 ptyfwd: always flush buffer and disconnect before exit
Then, it is not necessary to manually drain PTY forwarder by the user
side. Also, not necessary to free PTY forwarder earlier explicitly to
make it disconnected.
2024-12-18 20:28:07 +09:00
Yu Watanabe
4a4e7ec0e9 ptyfwd: always write additional line break on stop
Currently we do that in the user of PTY forwarder, e.g. nspawn.
But, let's do that unconditionally in the PTY forwarder.
2024-12-18 20:26:58 +09:00
Yu Watanabe
d517427dff ptyfwd: save the last character before the escape sequence
If we write e.g. a line break and CSI sequence, then it is not necessary
to write another line break on exit.
2024-12-18 19:55:46 +09:00
Yu Watanabe
5e6a48bf99 ptyfwd: do not forward partial escape sequence
Otherwise, if the sender is killed while writing escape sequence,
we may get spurious output.
2024-12-18 19:55:37 +09:00
Yu Watanabe
781c8c3f72 ptyfwd: coding style fix
- replace 'type *func()' -> 'type* func()',
- rename output argument to 'ret'.
2024-12-18 19:45:46 +09:00
Lennart Poettering
25b1a73f71 journald: get rid of get_process_capeff(), use pidref_get_capability() instead
This does pretty much the same, but is nicer, since it parses things
properly.
2024-12-17 19:06:54 +01:00
Lennart Poettering
a5370d35d6 capability-util: introduce capability_is_set() helper 2024-12-17 19:06:54 +01:00
Lennart Poettering
1184626a26 capability-util: generalize helper to acquire local caps
This generalizes and modernizes the code to acquire set of local caps,
based on the code for this in the condition logic. Uses PidRef, and
acquires the full quintuplet of caps.

This can be considered preparation to one day maybe build without
libcap.
2024-12-17 19:06:54 +01:00
Lennart Poettering
9311c28b34 hwdb: disable inclusion of the PCI domain in MANA network interface naming 2024-12-11 16:38:25 +01:00
Lennart Poettering
19491cc90f net_id: depending on new udev prop, include/exclude PCI domain from netif names 2024-12-11 16:37:59 +01:00
93 changed files with 2065 additions and 819 deletions

View File

@ -16,7 +16,7 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@07ef37c4c0dad5dfc6cec86c967a7600df1cd88c - uses: systemd/mkosi@7d45366395f29fdb2b534a850c09d23d29b78fa9
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space # Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
# immediately, we remove the files in the background. However, we first move them to a different location # immediately, we remove the files in the background. However, we first move them to a different location
@ -64,7 +64,7 @@ jobs:
MESON_OPTIONS=--werror MESON_OPTIONS=--werror
COVERAGE=1 COVERAGE=1
[Host] [Runtime]
QemuMem=4G QemuMem=4G
EOF EOF

View File

@ -113,7 +113,7 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@c4bbf3b71a3e2cf947995caedf10f69da3c4957a - uses: systemd/mkosi@7d45366395f29fdb2b534a850c09d23d29b78fa9
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space # Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
# immediately, we remove the files in the background. However, we first move them to a different location # immediately, we remove the files in the background. However, we first move them to a different location
@ -171,7 +171,7 @@ jobs:
[Content] [Content]
SELinuxRelabel=${{ matrix.relabel }} SELinuxRelabel=${{ matrix.relabel }}
[Host] [Runtime]
QemuMem=4G QemuMem=4G
EOF EOF

1
.gitignore vendored
View File

@ -7,6 +7,7 @@
.config.args .config.args
.gdb_history .gdb_history
.deps/ .deps/
.venv/
.mypy_cache/ .mypy_cache/
__pycache__/ __pycache__/
/*.gcda /*.gcda

6
TODO
View File

@ -446,10 +446,6 @@ Features:
* credentials: add a flag to the scoped credentials that if set require PK * credentials: add a flag to the scoped credentials that if set require PK
reauthentication when unlocking a secret. reauthentication when unlocking a secret.
* teach systemd --user to properly load credentials off disk, with
/etc/credstore equivalent and similar. Make sure that $CREDENTIALS_DIRECTORY=
actually works too when run with user privs.
* extend the smbios11 logic for passing credentials so that instead of passing * extend the smbios11 logic for passing credentials so that instead of passing
the credential data literally it can also just reference an AF_VSOCK CID/port the credential data literally it can also just reference an AF_VSOCK CID/port
to read them from. This way the data doesn't remain in the SMBIOS blob during to read them from. This way the data doesn't remain in the SMBIOS blob during
@ -795,7 +791,7 @@ Features:
* udevd: extend memory pressure logic: also kill any idle worker processes * udevd: extend memory pressure logic: also kill any idle worker processes
* udevadm: to make symlink querying with udevadm nicer: * udevadm: to make symlink querying with udevadm nicer:
- do not enable the pager for queries like 'udevadm info -q -r symlink' - do not enable the pager for queries like 'udevadm info -q symlink -r'
- add mode with newlines instead of spaces (for grep)? - add mode with newlines instead of spaces (for grep)?
* SIGRTMIN+18 and memory pressure handling should still be added to: hostnamed, * SIGRTMIN+18 and memory pressure handling should still be added to: hostnamed,

View File

@ -3,3 +3,7 @@
# Dell iDRAC Virtual USB NIC # Dell iDRAC Virtual USB NIC
usb:v413CpA102* usb:v413CpA102*
ID_NET_NAME_FROM_DATABASE=idrac ID_NET_NAME_FROM_DATABASE=idrac
# Disable inclusion of PCI domain in interface names on Azure MANA
pci:v00001414d000000BA*
ID_NET_NAME_INCLUDE_DOMAIN=0

View File

@ -10,7 +10,7 @@ sudo systemd-cryptsetup attach mytest /dev/sdXn - fido2-device=auto
# If that worked, let's now add the same line persistently to /etc/crypttab, # If that worked, let's now add the same line persistently to /etc/crypttab,
# for the future. We don't want to use the (unstable) /dev/sdX name, so let's # for the future. We don't want to use the (unstable) /dev/sdX name, so let's
# figure out a stable link: # figure out a stable link:
udevadm info -q -r symlink /dev/sdXn udevadm info -q symlink -r /dev/sdXn
# Now add the line using the by-uuid symlink to /etc/crypttab: # Now add the line using the by-uuid symlink to /etc/crypttab:
sudo bash -c 'echo "mytest /dev/disk/by-uuid/... - fido2-device=auto" >>/etc/crypttab' sudo bash -c 'echo "mytest /dev/disk/by-uuid/... - fido2-device=auto" >>/etc/crypttab'

View File

@ -97,6 +97,18 @@
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>systemd.break=</varname></term>
<term><varname>rd.systemd.break=</varname></term>
<listitem>
<para>Parameters understood by
<citerefentry><refentrytitle>systemd-debug-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
to pause the boot process at a certain point and spawn a debug shell.</para>
<xi:include href="version-info.xml" xpointer="v258"/>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>systemd.run=</varname></term> <term><varname>systemd.run=</varname></term>
<term><varname>systemd.run_success_action=</varname></term> <term><varname>systemd.run_success_action=</varname></term>

View File

@ -205,6 +205,11 @@
<arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="plain">smbios11</arg> <arg choice="plain">smbios11</arg>
</cmdsynopsis> </cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="plain">chid</arg>
</cmdsynopsis>
</refsynopsisdiv> </refsynopsisdiv>
<refsect1> <refsect1>
@ -1084,6 +1089,37 @@ io.systemd.credential:vmm.notify_socket=vsock-stream:2:254570042
<xi:include href="version-info.xml" xpointer="v257"/> <xi:include href="version-info.xml" xpointer="v257"/>
</refsect2> </refsect2>
<refsect2>
<title><command>systemd-analyze chid</command></title>
<para>Shows a list of Computer Hardware IDs (CHIDs) of the local system. These IDs identify the
system's computer hardware, based on SMBIOS data. See <ulink
url="https://learn.microsoft.com/en-us/windows-hardware/drivers/dashboard/using-chids">Using Computer
Hardware IDs (CHIDs)</ulink> for details about CHIDs.</para>
<example>
<title>Example output</title>
<programlisting>$ systemd-analyze chid
TYPE INPUT CHID
3 MFPSmp 520537c0-3b59-504f-b062-9682ea236b21
4 MFPS-- edf05dc8-a53d-5b2c-8023-630bca2a2463
5 MFP--- ebc6a4d9-ec48-537a-916b-c69fa4fdd814
6 M--Smp 5ebe4bba-f598-5e90-9ff2-9fd0d3211465
7 M--S-- 1a3fb835-b42a-5f9c-a38c-eff5bfd5c41d
8 M-P-mp 2a831dce-8163-5bad-8406-435b8c752dd8
9 M-P--- 7c21c878-4a75-50f7-9816-21e811588da0
10 MF--mp 9a003537-bcc5-500e-b10a-8d8892e4fc64
11 MF---- bb9122bb-8a5c-50d2-a742-a85beb719909
13 M---mp bfc36935-5032-5987-a0a3-6311f01de33a
LEGEND: M → sys_vendor (LENOVO) ┄ F → product_family (ThinkPad X1 Carbon Gen 9) ┄ P → product_name (20XW0055GE)
S → product_sku (LENOVO_MT_20XW_BU_Think_FM_ThinkPad X1 Carbon Gen 9) ┄ m → board_vendor (LENOVO)
p → board_name (20XW0055GE)</programlisting>
</example>
<xi:include href="version-info.xml" xpointer="v258"/>
</refsect2>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -31,45 +31,131 @@
<refsect1> <refsect1>
<title>Description</title> <title>Description</title>
<para><filename>systemd-debug-generator</filename> is a generator <para><command>systemd-debug-generator</command> is a generator that provides some debugging
that reads the kernel command line and understands three functionality.</para>
options:</para>
<para>If the <option>systemd.mask=</option> or <option>rd.systemd.mask=</option> <para><command>systemd-debug-generator</command> implements
option is specified and followed by a unit name, this unit is
masked for the runtime (i.e. for this session — from boot to shutdown), similarly to the effect of
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>mask</command> command. This is useful to boot with
certain units removed from the initial boot transaction for
debugging system startup. May be specified more than once.
<option>rd.systemd.mask=</option> is honored only by initial
RAM disk (initrd) while <option>systemd.mask=</option> is
honored only in the main system.</para>
<para>If the <option>systemd.wants=</option> or
<option>rd.systemd.wants=</option> option is specified
and followed by a unit name, a start job for this unit is added to
the initial transaction. This is useful to start one or more
additional units at boot. May be specified more than once.
<option>rd.systemd.wants=</option> is honored only by initial
RAM disk (initrd) while <option>systemd.wants=</option> is
honored only in the main system.</para>
<para>If the <option>systemd.debug_shell</option> or <option>rd.systemd.debug_shell</option> option is
specified, the debug shell service <literal>debug-shell.service</literal> is pulled into the boot
transaction and a debug shell will be spawned during early boot. By default,
<filename>&DEBUGTTY;</filename> is used, but a specific tty can also be specified, either with or without
the <filename>/dev/</filename> prefix. To set the tty to use without enabling the debug shell, the
<option>systemd.default_debug_tty=</option> option can be used which also takes a tty with or without the
<filename>/dev/</filename> prefix. Note that the shell may also be turned on persistently by enabling it
with <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>enable</command> command. <option>rd.systemd.debug_shell</option> is honored only by initial
RAM disk (initrd) while <option>systemd.debug_shell</option> is honored only in the main system.</para>
<para><filename>systemd-debug-generator</filename> implements
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para> <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1> </refsect1>
<refsect1>
<title>Kernel Command Line</title>
<para><command>systemd-debug-generator</command> understands the following kernel command line
parameters:</para>
<variablelist class='kernel-commandline-options'>
<varlistentry>
<term><varname>systemd.mask=</varname></term>
<term><varname>rd.systemd.mask=</varname></term>
<listitem><para>These options take a unit name as argument. The unit specified is masked for the
runtime (i.e. for this session — from boot to shutdown), similarly to the effect of
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>mask</command> command. This is useful to boot with certain units removed from the initial
boot transaction for debugging system startup. May be specified more than once. The option prefixed
with <literal>rd.</literal> is honored only in the initrd, while the one without prefix is only
honored in the main system.</para>
<xi:include href="version-info.xml" xpointer="v215"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.wants=</varname></term>
<term><varname>rd.systemd.wants=</varname></term>
<listitem><para>These options take a unit name as argument. A start job for this unit is added to the
initial transaction. This is useful to start one or more additional units at boot. May be specified
more than once. The option prefixed with <literal>rd.</literal> is honored only in the initrd, while
the one that is not prefixed only in the main system.</para>
<xi:include href="version-info.xml" xpointer="v215"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.debug_shell</varname></term>
<term><varname>rd.systemd.debug_shell</varname></term>
<term><varname>systemd.default_debug_tty=</varname></term>
<term><varname>rd.systemd.default_debug_tty=</varname></term>
<listitem><para>If the <option>systemd.debug_shell</option> or
<option>rd.systemd.debug_shell</option> option is specified, the debug shell service
<literal>debug-shell.service</literal> is pulled into the boot transaction and a debug shell will be
spawned during early boot. By default, <filename>&DEBUGTTY;</filename> is used, but a specific tty
can also be specified, either with or without the <filename>/dev/</filename> prefix. To set the tty
to use without enabling the debug shell, the <option>systemd.default_debug_tty=</option> option can
be used which also takes a tty with or without the <filename>/dev/</filename> prefix. Note that the
shell may also be turned on persistently by enabling it with
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>enable</command> command. The options prefixed with <literal>rd.</literal> are honored only
in the initrd, while the ones without prefix are only honored in the main system.</para>
<xi:include href="version-info.xml" xpointer="v215"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.break=</varname></term>
<term><varname>rd.systemd.break=</varname></term>
<listitem><para>Takes one of <option>pre-udev</option>, <option>pre-basic</option>,
<option>pre-mount</option>, or <option>pre-switch-root</option> (the default for the
<literal>rd.</literal> option). It also accepts multiple values separated by comma
(<literal>,</literal>). These options allow to pause the boot process at a certain point and spawn a
debug shell. After exiting this shell, the system will resume booting. The option prefixed with
<literal>rd.</literal> is honored only in the initrd, while the one without prefix is only honored in
the main system.</para>
<table>
<title>Available breakpoints</title>
<tgroup cols='4'>
<colspec colname='breakpoint' />
<colspec colname='description' />
<colspec colname='initrd' />
<colspec colname='main' />
<thead>
<row>
<entry>Breakpoints</entry>
<entry>Description</entry>
<entry>Can be used in the initrd</entry>
<entry>Can be used in the main system</entry>
</row>
</thead>
<tbody>
<row>
<entry><option>pre-udev</option></entry>
<entry>Before starting to process kernel uevents, i.e., before <filename>systemd-udevd.service</filename> starts.</entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry><option>pre-basic</option></entry>
<entry>Before leaving early boot and regular services start, i.e., before <filename>basic.target</filename> is reached.</entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry><option>pre-mount</option></entry>
<entry>Before the root filesystem is mounted, i.e., before <filename>sysroot.mount</filename> starts.</entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry><option>pre-switch-root</option></entry>
<entry>Before switching from the initrd to the real root.</entry>
<entry></entry>
<entry></entry>
</row>
</tbody>
</tgroup>
</table>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1> <refsect1>
<title>System Credentials</title> <title>System Credentials</title>
@ -108,6 +194,8 @@
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member> <member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member> <member><citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry></member> <member><citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
</simplelist></para> </simplelist></para>
</refsect1> </refsect1>

View File

@ -3468,37 +3468,43 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
<term><varname>LoadCredentialEncrypted=</varname><replaceable>ID</replaceable><optional>:<replaceable>PATH</replaceable></optional></term> <term><varname>LoadCredentialEncrypted=</varname><replaceable>ID</replaceable><optional>:<replaceable>PATH</replaceable></optional></term>
<listitem><para>Pass a credential to the unit. Credentials are limited-size binary or textual objects <listitem><para>Pass a credential to the unit. Credentials are limited-size binary or textual objects
that may be passed to unit processes. They are primarily used for passing cryptographic keys (both that may be passed to unit processes. They are primarily intended for passing cryptographic keys
public and private) or certificates, user account information or identity information from host to (both public and private) or certificates, user account information or identity information from host
services. The data is accessible from the unit's processes via the file system, at a read-only to services, but can be freely used to pass any kind of limited-size information to a service. The
location that (if possible and permitted) is backed by non-swappable memory. The data is only data is accessible from the unit's processes via the file system, at a read-only location that (if
accessible to the user associated with the unit, via the possible and permitted) is backed by non-swappable memory. The data is only accessible to the user
<varname>User=</varname>/<varname>DynamicUser=</varname> settings (as well as the superuser). When associated with the unit, via the <varname>User=</varname>/<varname>DynamicUser=</varname> settings
available, the location of credentials is exported as the <varname>$CREDENTIALS_DIRECTORY</varname> (as well as the superuser). When available, the location of credentials is exported as the
environment variable to the unit's processes.</para> <varname>$CREDENTIALS_DIRECTORY</varname> environment variable to the unit's processes.</para>
<para>The <varname>LoadCredential=</varname> setting takes a textual ID to use as name for a <para>The <varname>LoadCredential=</varname> setting takes a textual ID to use as name for a
credential plus a file system path, separated by a colon. The ID must be a short ASCII string credential plus a file system path, separated by a colon. The ID must be a short ASCII string
suitable as filename in the filesystem, and may be chosen freely by the user. If the specified path suitable as filename in the filesystem, and may be chosen freely by the user. If the specified path
is absolute it is opened as regular file and the credential data is read from it. If the absolute is absolute it is opened as regular file and the credential data is read from it. If the absolute
path refers to an <constant>AF_UNIX</constant> stream socket in the file system a connection is made path refers to an <constant>AF_UNIX</constant> stream socket in the file system a connection is made
to it (only once at unit start-up) and the credential data read from the connection, providing an to it (once at process invocation) and the credential data read from the connection, providing an
easy IPC integration point for dynamically transferring credentials from other services.</para> easy IPC integration point for dynamically transferring credentials from other services.</para>
<para>If the specified path is not absolute and itself qualifies as valid credential identifier it is <para>If the specified path is not absolute and itself qualifies as valid credential identifier it is
attempted to find a credential that the service manager itself received under the specified name — attempted to find a credential that the service manager itself received under the specified name —
which may be used to propagate credentials from an invoking environment (e.g. a container manager which may be used to propagate credentials from an invoking environment (e.g. a container manager
that invoked the service manager) into a service. If no matching system credential is found, the that invoked the service manager) into a service. If no matching passed credential is found, the
directories <filename>/etc/credstore/</filename>, <filename>/run/credstore/</filename> and system service manager will search the directories <filename>/etc/credstore/</filename>,
<filename>/usr/lib/credstore/</filename> are searched for files under the credential's name — which <filename>/run/credstore/</filename> and <filename>/usr/lib/credstore/</filename> for files under the
hence are recommended locations for credential data on disk. If credential's name — which hence are recommended locations for credential data on disk. If
<varname>LoadCredentialEncrypted=</varname> is used <filename>/run/credstore.encrypted/</filename>, <varname>LoadCredentialEncrypted=</varname> is used <filename>/run/credstore.encrypted/</filename>,
<filename>/etc/credstore.encrypted/</filename>, and <filename>/etc/credstore.encrypted/</filename>, and
<filename>/usr/lib/credstore.encrypted/</filename> are searched as well.</para> <filename>/usr/lib/credstore.encrypted/</filename> are searched as well. The per-user service manager
will search <filename>$XDG_CONFIG_HOME/credstore/</filename>,
<filename>$XDG_RUNTIME_DIR/credstore/</filename>, <filename>$HOME/.local/lib/credstore/</filename>
(and the counterparts ending with <filename>…/credstore.encrypted/</filename>) instead. The
<citerefentry><refentrytitle>systemd-path</refentrytitle><manvolnum>1</manvolnum></citerefentry> tool
may be used to query the precise credential store search path.</para>
<para>If the file system path is omitted it is chosen identical to the credential name, i.e. this is <para>If the file system path is omitted it is chosen identical to the credential name, i.e. this is
a terse way to declare credentials to inherit from the service manager into a service. This option a terse way to declare credentials to inherit from the service manager or credstore directories into
may be used multiple times, each time defining an additional credential to pass to the unit.</para> a service. This option may be used multiple times, each time defining an additional credential to
pass to the unit.</para>
<para>Note that if the path is not specified or a valid credential identifier is given, i.e. <para>Note that if the path is not specified or a valid credential identifier is given, i.e.
in the above two cases, a missing credential is not considered fatal.</para> in the above two cases, a missing credential is not considered fatal.</para>

View File

@ -64,6 +64,10 @@
override existing definitions. For tests, generators may be called with just one argument; the generator override existing definitions. For tests, generators may be called with just one argument; the generator
should assume that all three paths are the same in that case.</para> should assume that all three paths are the same in that case.</para>
<para>Generators executed by the system manager are invoked in a sandbox with a private writable
<filename>/tmp/</filename> directory and where most of the file system is read-only except for the
generator output directories.</para>
<para>Directory paths for generator output differ by priority: <filename>…/generator.early</filename> has <para>Directory paths for generator output differ by priority: <filename>…/generator.early</filename> has
priority higher than the admin configuration in <filename>/etc/</filename>, while priority higher than the admin configuration in <filename>/etc/</filename>, while
<filename>…/generator</filename> has lower priority than <filename>/etc/</filename> but higher than <filename>…/generator</filename> has lower priority than <filename>/etc/</filename> but higher than

View File

@ -672,7 +672,7 @@
<listitem><para>Specifies what anchor point <varname>Path=</varname> should be relative to. Takes one <listitem><para>Specifies what anchor point <varname>Path=</varname> should be relative to. Takes one
of <constant>root</constant>, <constant>esp</constant>, <constant>xbootldr</constant>, of <constant>root</constant>, <constant>esp</constant>, <constant>xbootldr</constant>,
<constant>boot</constant> or <constant>directory</constant>. If unspecified, defaults to <constant>boot</constant> or <constant>explicit</constant>. If unspecified, defaults to
<constant>root</constant>.</para> <constant>root</constant>.</para>
<para>If set to <constant>root</constant>, <constant>esp</constant>, <constant>xbootldr</constant>, <para>If set to <constant>root</constant>, <constant>esp</constant>, <constant>xbootldr</constant>,

View File

@ -93,7 +93,7 @@
XML file. XML file.
This may be used by software centers (such as GNOME Software or KDE Discover) to present rich This may be used by software centers (such as GNOME Software or KDE Discover) to present rich
metadata about this feature. metadata about this feature.
This includes display names, chagnelogs, icons, and more. This includes display names, changelogs, icons, and more.
This setting supports specifier expansion; see below for details on supported specifiers.</para> This setting supports specifier expansion; see below for details on supported specifiers.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem> <xi:include href="version-info.xml" xpointer="v257"/></listitem>
@ -177,7 +177,7 @@ Enabled=false
</programlisting></para> </programlisting></para>
<para>The above defines the <literal>devel</literal> feature, and disables it by default. <para>The above defines the <literal>devel</literal> feature, and disables it by default.
Now let's a define a transfer that's associated with this feature:</para> Now let's define a transfer that's associated with this feature:</para>
<para><programlisting># /usr/lib/sysupdate.d/50-devel.transfer <para><programlisting># /usr/lib/sysupdate.d/50-devel.transfer
[Transfer] [Transfer]

View File

@ -10,7 +10,7 @@ sudo systemd-cryptsetup attach mytest /dev/sdXn - tpm2-device=auto
# If that worked, let's now add the same line persistently to /etc/crypttab, # If that worked, let's now add the same line persistently to /etc/crypttab,
# for the future. We don't want to use the (unstable) /dev/sdX name, so let's # for the future. We don't want to use the (unstable) /dev/sdX name, so let's
# figure out a stable link: # figure out a stable link:
udevadm info -q -r symlink /dev/sdXn udevadm info -q symlink -r /dev/sdXn
# Now add the line using the by-uuid symlink to /etc/crypttab: # Now add the line using the by-uuid symlink to /etc/crypttab:
sudo bash -c 'echo "mytest /dev/disk/by-uuid/... - tpm2-device=auto" >>/etc/crypttab' sudo bash -c 'echo "mytest /dev/disk/by-uuid/... - tpm2-device=auto" >>/etc/crypttab'

View File

@ -26,7 +26,7 @@ sudo systemd-cryptsetup attach mytest /dev/sdXn - pkcs11-uri=auto
# If that worked, let's now add the same line persistently to /etc/crypttab, # If that worked, let's now add the same line persistently to /etc/crypttab,
# for the future. We don't want to use the (unstable) /dev/sdX name, so let's # for the future. We don't want to use the (unstable) /dev/sdX name, so let's
# figure out a stable link: # figure out a stable link:
udevadm info -q -r symlink /dev/sdXn udevadm info -q symlink -r /dev/sdXn
# Now add the line using the by-uuid symlink to /etc/crypttab: # Now add the line using the by-uuid symlink to /etc/crypttab:
sudo bash -c 'echo "mytest /dev/disk/by-uuid/... - pkcs11-uri=auto" >>/etc/crypttab' sudo bash -c 'echo "mytest /dev/disk/by-uuid/... - pkcs11-uri=auto" >>/etc/crypttab'

View File

@ -130,7 +130,7 @@ Packages=
zsh zsh
zstd zstd
[Host] [Runtime]
Credentials= Credentials=
journal.storage=persistent journal.storage=persistent
tty.serial.hvc0.agetty.autologin=root tty.serial.hvc0.agetty.autologin=root

View File

@ -8,8 +8,8 @@ msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-28 18:16+0900\n" "POT-Creation-Date: 2024-11-28 18:16+0900\n"
"PO-Revision-Date: 2024-11-20 19:13+0000\n" "PO-Revision-Date: 2024-12-20 15:38+0000\n"
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>\n" "Last-Translator: Ricky Tigg <ricky.tigg@gmail.com>\n"
"Language-Team: Finnish <https://translate.fedoraproject.org/projects/systemd/" "Language-Team: Finnish <https://translate.fedoraproject.org/projects/systemd/"
"main/fi/>\n" "main/fi/>\n"
"Language: fi\n" "Language: fi\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.8.2\n" "X-Generator: Weblate 5.9.1\n"
#: src/core/org.freedesktop.systemd1.policy.in:22 #: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system" msgid "Send passphrase back to system"
@ -1176,9 +1176,8 @@ msgid "Manage optional features"
msgstr "Hallitse valinnaisia ominaisuuksia" msgstr "Hallitse valinnaisia ominaisuuksia"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76 #: src/sysupdate/org.freedesktop.sysupdate1.policy:76
#, fuzzy
msgid "Authentication is required to manage optional features." msgid "Authentication is required to manage optional features."
msgstr "Todennus vaaditaan valinnaisten ominaisuuksien hallintaan" msgstr "Todennus vaaditaan valinnaisten ominaisuuksien hallintaan."
#: src/timedate/org.freedesktop.timedate1.policy:22 #: src/timedate/org.freedesktop.timedate1.policy:22
msgid "Set system time" msgid "Set system time"

View File

@ -67,7 +67,7 @@ _systemd_analyze() {
) )
local -A VERBS=( local -A VERBS=(
[STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk has-tpm2 smbios11' [STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk has-tpm2 smbios11 chid'
[CRITICAL_CHAIN]='critical-chain' [CRITICAL_CHAIN]='critical-chain'
[DOT]='dot' [DOT]='dot'
[DUMP]='dump' [DUMP]='dump'

224
src/analyze/analyze-chid.c Normal file
View File

@ -0,0 +1,224 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "analyze.h"
#include "analyze-chid.h"
#include "chid-fundamental.h"
#include "efi-api.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
#include "parse-util.h"
#include "strv.h"
#include "utf8.h"
#include "virt.h"
static int parse_chid_type(const char *s, size_t *ret) {
unsigned u;
int r;
assert(s);
r = safe_atou(s, &u);
if (r < 0)
return r;
if (u >= CHID_TYPES_MAX)
return -ERANGE;
if (ret)
*ret = u;
return 0;
}
static const char chid_smbios_fields_char[_CHID_SMBIOS_FIELDS_MAX] = {
[CHID_SMBIOS_MANUFACTURER] = 'M',
[CHID_SMBIOS_FAMILY] = 'F',
[CHID_SMBIOS_PRODUCT_NAME] = 'P',
[CHID_SMBIOS_PRODUCT_SKU] = 'S',
[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = 'm',
[CHID_SMBIOS_BASEBOARD_PRODUCT] = 'p',
};
static char *chid_smbios_fields_string(uint32_t combination) {
_cleanup_free_ char *s = NULL;
for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) {
char c;
c = (combination & (UINT32_C(1) << f)) ? chid_smbios_fields_char[f] : '-';
if (!strextend(&s, CHAR_TO_STR(c)))
return NULL;
}
return TAKE_PTR(s);
}
static int add_chid(Table *table, const EFI_GUID guids[static CHID_TYPES_MAX], size_t t) {
int r;
assert(table);
assert(guids);
assert(t < CHID_TYPES_MAX);
sd_id128_t id = efi_guid_to_id128(guids + t);
if (sd_id128_is_null(id))
return 0;
_cleanup_free_ char *flags = chid_smbios_fields_string(chid_smbios_table[t]);
if (!flags)
return log_oom();
r = table_add_many(table,
TABLE_UINT, (unsigned) t,
TABLE_STRING, flags,
TABLE_UUID, id);
if (r < 0)
return table_log_add_error(r);
return 0;
}
static void smbios_fields_free(char16_t *(*fields)[_CHID_SMBIOS_FIELDS_MAX]) {
assert(fields);
FOREACH_ARRAY(i, *fields, _CHID_SMBIOS_FIELDS_MAX)
free(*i);
}
int verb_chid(int argc, char *argv[], void *userdata) {
static const char *const smbios_files[_CHID_SMBIOS_FIELDS_MAX] = {
[CHID_SMBIOS_MANUFACTURER] = "sys_vendor",
[CHID_SMBIOS_FAMILY] = "product_family",
[CHID_SMBIOS_PRODUCT_NAME] = "product_name",
[CHID_SMBIOS_PRODUCT_SKU] = "product_sku",
[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = "board_vendor",
[CHID_SMBIOS_BASEBOARD_PRODUCT] = "board_name",
};
_cleanup_(table_unrefp) Table *table = NULL;
int r;
if (detect_container() > 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Container environments do not have SMBIOS.");
table = table_new("type", "input", "chid");
if (!table)
return log_oom();
(void) table_set_align_percent(table, table_get_cell(table, 0, 0), 100);
(void) table_set_align_percent(table, table_get_cell(table, 0, 1), 50);
_cleanup_close_ int smbios_fd = open("/sys/class/dmi/id", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (smbios_fd < 0)
return log_error_errno(errno, "Failed to open SMBIOS sysfs object: %m");
_cleanup_(smbios_fields_free) char16_t* smbios_fields[_CHID_SMBIOS_FIELDS_MAX] = {};
for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) {
_cleanup_free_ char *buf = NULL;
size_t size;
r = read_virtual_file_at(smbios_fd, smbios_files[f], SIZE_MAX, &buf, &size);
if (r < 0)
return log_error_errno(r, "Failed to read SMBIOS field '%s': %m", smbios_files[f]);
if (size < 1 || buf[size-1] != '\n')
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected SMBIOS field '%s' to end in newline, but it doesn't, refusing.", smbios_files[f]);
size--;
smbios_fields[f] = utf8_to_utf16(buf, size);
if (!smbios_fields[f])
return log_oom();
}
EFI_GUID chids[CHID_TYPES_MAX] = {};
chid_calculate((const char16_t* const*) smbios_fields, chids);
if (strv_isempty(strv_skip(argv, 1)))
for (size_t t = 0; t < CHID_TYPES_MAX; t++) {
r = add_chid(table, chids, t);
if (r < 0)
return r;
}
else {
STRV_FOREACH(as, strv_skip(argv, 1)) {
size_t t;
r = parse_chid_type(*as, &t);
if (r < 0)
return log_error_errno(r, "Failed to pare CHID type: %s", *as);
r = add_chid(table, chids, t);
if (r < 0)
return r;
}
(void) table_set_sort(table, (size_t) 0);
}
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
if (r < 0)
return log_error_errno(r, "Failed to output table: %m");
if (!sd_json_format_enabled(arg_json_format_flags)) {
_cleanup_free_ char *legend = NULL;
bool separator = false;
size_t w = 0;
legend = strjoin(ansi_grey(), "LEGEND: ", ansi_normal());
if (!legend)
return log_oom();
for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) {
_cleanup_free_ char *c = utf16_to_utf8(smbios_fields[f], SIZE_MAX);
if (!c)
return log_oom();
if (!strextend(&legend,
ansi_grey(),
separator ? " " : "",
separator ? special_glyph(SPECIAL_GLYPH_HORIZONTAL_DOTTED) : "",
separator ? " " : "",
ansi_normal(),
CHAR_TO_STR(chid_smbios_fields_char[f]),
ansi_grey(),
" ",
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
" ",
ansi_normal(),
smbios_files[f],
ansi_grey(),
" (",
ansi_highlight(),
c,
ansi_grey(),
")",
ansi_normal()))
return log_oom();
w += separator * 3 +
4 +
utf8_console_width(smbios_files[f]) +
2 +
utf8_console_width(c) +
1;
if (w > 79) {
if (!strextend(&legend, "\n "))
return log_oom();
separator = false;
w = 8;
} else
separator = true;
}
putchar('\n');
puts(legend);
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
int verb_chid(int argc, char *argv[], void *userdata);

View File

@ -18,6 +18,7 @@
#include "analyze-calendar.h" #include "analyze-calendar.h"
#include "analyze-capability.h" #include "analyze-capability.h"
#include "analyze-cat-config.h" #include "analyze-cat-config.h"
#include "analyze-chid.h"
#include "analyze-compare-versions.h" #include "analyze-compare-versions.h"
#include "analyze-condition.h" #include "analyze-condition.h"
#include "analyze-critical-chain.h" #include "analyze-critical-chain.h"
@ -219,6 +220,7 @@ static int help(int argc, char *argv[], void *userdata) {
" filesystems [NAME...] List known filesystems\n" " filesystems [NAME...] List known filesystems\n"
" architectures [NAME...] List known architectures\n" " architectures [NAME...] List known architectures\n"
" smbios11 List strings passed via SMBIOS Type #11\n" " smbios11 List strings passed via SMBIOS Type #11\n"
" chid List local CHIDs\n"
"\n%3$sExpression Evaluation:%4$s\n" "\n%3$sExpression Evaluation:%4$s\n"
" condition CONDITION... Evaluate conditions and asserts\n" " condition CONDITION... Evaluate conditions and asserts\n"
" compare-versions VERSION1 [OP] VERSION2\n" " compare-versions VERSION1 [OP] VERSION2\n"
@ -593,10 +595,6 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --offline= requires one or more units to perform a security review."); "Option --offline= requires one or more units to perform a security review.");
if (sd_json_format_enabled(arg_json_format_flags) && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf", "plot", "fdstore", "pcrs", "architectures", "capability", "exit-status"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --json= is only supported for security, inspect-elf, plot, fdstore, pcrs, architectures, capability, exit-status right now.");
if (arg_threshold != 100 && !streq_ptr(argv[optind], "security")) if (arg_threshold != 100 && !streq_ptr(argv[optind], "security"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --threshold= is only supported for security right now."); "Option --threshold= is only supported for security right now.");
@ -631,10 +629,6 @@ static int parse_argv(int argc, char *argv[]) {
if (streq_ptr(argv[optind], "condition") && arg_unit && optind < argc - 1) if (streq_ptr(argv[optind], "condition") && arg_unit && optind < argc - 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No conditions can be passed if --unit= is used."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No conditions can be passed if --unit= is used.");
if ((!arg_legend && !STRPTR_IN_SET(argv[optind], "plot", "architectures")) ||
(streq_ptr(argv[optind], "plot") && !arg_legend && !arg_table && !sd_json_format_enabled(arg_json_format_flags)))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --no-legend is only supported for plot with either --table or --json=.");
if (arg_table && !streq_ptr(argv[optind], "plot")) if (arg_table && !streq_ptr(argv[optind], "plot"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --table is only supported for plot right now."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --table is only supported for plot right now.");
@ -691,6 +685,7 @@ static int run(int argc, char *argv[]) {
{ "srk", VERB_ANY, 1, 0, verb_srk }, { "srk", VERB_ANY, 1, 0, verb_srk },
{ "architectures", VERB_ANY, VERB_ANY, 0, verb_architectures }, { "architectures", VERB_ANY, VERB_ANY, 0, verb_architectures },
{ "smbios11", VERB_ANY, 1, 0, verb_smbios11 }, { "smbios11", VERB_ANY, 1, 0, verb_smbios11 },
{ "chid", VERB_ANY, VERB_ANY, 0, verb_chid },
{} {}
}; };

View File

@ -6,6 +6,7 @@ systemd_analyze_sources = files(
'analyze-calendar.c', 'analyze-calendar.c',
'analyze-capability.c', 'analyze-capability.c',
'analyze-cat-config.c', 'analyze-cat-config.c',
'analyze-chid.c',
'analyze-compare-versions.c', 'analyze-compare-versions.c',
'analyze-condition.c', 'analyze-condition.c',
'analyze-critical-chain.c', 'analyze-critical-chain.c',

View File

@ -9,8 +9,8 @@
#define AUDIT_SESSION_INVALID UINT32_MAX #define AUDIT_SESSION_INVALID UINT32_MAX
int audit_session_from_pid(const PidRef *pid, uint32_t *id); int audit_session_from_pid(const PidRef *pid, uint32_t *ret_id);
int audit_loginuid_from_pid(const PidRef *pid, uid_t *uid); int audit_loginuid_from_pid(const PidRef *pid, uid_t *ret_uid);
bool use_audit(void); bool use_audit(void);

View File

@ -8,8 +8,9 @@
#include <unistd.h> #include <unistd.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "capability-util.h"
#include "cap-list.h" #include "cap-list.h"
#include "capability-util.h"
#include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "log.h" #include "log.h"
#include "logarithm.h" #include "logarithm.h"
@ -17,6 +18,8 @@
#include "missing_prctl.h" #include "missing_prctl.h"
#include "missing_threads.h" #include "missing_threads.h"
#include "parse-util.h" #include "parse-util.h"
#include "pidref.h"
#include "stat-util.h"
#include "user-util.h" #include "user-util.h"
int have_effective_cap(int value) { int have_effective_cap(int value) {
@ -607,3 +610,78 @@ int capability_get_ambient(uint64_t *ret) {
*ret = a; *ret = a;
return 1; return 1;
} }
int pidref_get_capability(const PidRef *pidref, CapabilityQuintet *ret) {
int r;
if (!pidref_is_set(pidref))
return -ESRCH;
if (pidref_is_remote(pidref))
return -EREMOTE;
const char *path = procfs_file_alloca(pidref->pid, "status");
_cleanup_fclose_ FILE *f = fopen(path, "re");
if (!f) {
if (errno == ENOENT && proc_mounted() == 0)
return -ENOSYS;
return -errno;
}
CapabilityQuintet q = CAPABILITY_QUINTET_NULL;
for (;;) {
_cleanup_free_ char *line = NULL;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return r;
if (r == 0)
break;
static const struct {
const char *field;
size_t offset;
} fields[] = {
{ "CapBnd:", offsetof(CapabilityQuintet, bounding) },
{ "CapInh:", offsetof(CapabilityQuintet, inheritable) },
{ "CapPrm:", offsetof(CapabilityQuintet, permitted) },
{ "CapEff:", offsetof(CapabilityQuintet, effective) },
{ "CapAmb:", offsetof(CapabilityQuintet, ambient) },
};
FOREACH_ELEMENT(i, fields) {
const char *p = first_word(line, i->field);
if (!p)
continue;
uint64_t *v = (uint64_t*) ((uint8_t*) &q + i->offset);
if (*v != CAP_MASK_UNSET)
return -EBADMSG;
r = safe_atoux64(p, v);
if (r < 0)
return r;
if (*v == CAP_MASK_UNSET)
return -EBADMSG;
}
}
if (q.effective == CAP_MASK_UNSET ||
q.inheritable == CAP_MASK_UNSET ||
q.permitted == CAP_MASK_UNSET ||
q.effective == CAP_MASK_UNSET ||
q.ambient == CAP_MASK_UNSET)
return -EBADMSG;
r = pidref_verify(pidref);
if (r < 0)
return r;
if (ret)
*ret = q;
return 0;
}

View File

@ -8,6 +8,7 @@
#include "macro.h" #include "macro.h"
#include "missing_capability.h" #include "missing_capability.h"
#include "pidref.h"
/* Special marker used when storing a capabilities mask as "unset" */ /* Special marker used when storing a capabilities mask as "unset" */
#define CAP_MASK_UNSET UINT64_MAX #define CAP_MASK_UNSET UINT64_MAX
@ -66,14 +67,18 @@ typedef struct CapabilityQuintet {
assert_cc(CAP_LAST_CAP < 64); assert_cc(CAP_LAST_CAP < 64);
#define CAPABILITY_QUINTET_NULL { CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET } #define CAPABILITY_QUINTET_NULL (CapabilityQuintet) { CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET }
static inline bool capability_is_set(uint64_t v) {
return v != CAP_MASK_UNSET;
}
static inline bool capability_quintet_is_set(const CapabilityQuintet *q) { static inline bool capability_quintet_is_set(const CapabilityQuintet *q) {
return q->effective != CAP_MASK_UNSET || return capability_is_set(q->effective) ||
q->bounding != CAP_MASK_UNSET || capability_is_set(q->bounding) ||
q->inheritable != CAP_MASK_UNSET || capability_is_set(q->inheritable) ||
q->permitted != CAP_MASK_UNSET || capability_is_set(q->permitted) ||
q->ambient != CAP_MASK_UNSET; capability_is_set(q->ambient);
} }
/* Mangles the specified caps quintet taking the current bounding set into account: /* Mangles the specified caps quintet taking the current bounding set into account:
@ -84,3 +89,5 @@ bool capability_quintet_mangle(CapabilityQuintet *q);
int capability_quintet_enforce(const CapabilityQuintet *q); int capability_quintet_enforce(const CapabilityQuintet *q);
int capability_get_ambient(uint64_t *ret); int capability_get_ambient(uint64_t *ret);
int pidref_get_capability(const PidRef *pidref, CapabilityQuintet *ret);

View File

@ -500,22 +500,6 @@ int pidref_is_kernel_thread(const PidRef *pid) {
return result; return result;
} }
int get_process_capeff(pid_t pid, char **ret) {
const char *p;
int r;
assert(pid >= 0);
assert(ret);
p = procfs_file_alloca(pid, "status");
r = get_proc_field(p, "CapEff", WHITESPACE, ret);
if (r == -ENOENT)
return -ESRCH;
return r;
}
static int get_process_link_contents(pid_t pid, const char *proc_file, char **ret) { static int get_process_link_contents(pid_t pid, const char *proc_file, char **ret) {
const char *p; const char *p;
int r; int r;

View File

@ -50,7 +50,6 @@ int get_process_exe(pid_t pid, char **ret);
int pid_get_uid(pid_t pid, uid_t *ret); int pid_get_uid(pid_t pid, uid_t *ret);
int pidref_get_uid(const PidRef *pid, uid_t *ret); int pidref_get_uid(const PidRef *pid, uid_t *ret);
int get_process_gid(pid_t pid, gid_t *ret); int get_process_gid(pid_t pid, gid_t *ret);
int get_process_capeff(pid_t pid, char **ret);
int get_process_cwd(pid_t pid, char **ret); int get_process_cwd(pid_t pid, char **ret);
int get_process_root(pid_t pid, char **ret); int get_process_root(pid_t pid, char **ret);
int get_process_environ(pid_t pid, char **ret); int get_process_environ(pid_t pid, char **ret);

View File

@ -85,7 +85,9 @@ static int device_set_sysfs(Device *d, const char *sysfs) {
Unit *u = UNIT(ASSERT_PTR(d)); Unit *u = UNIT(ASSERT_PTR(d));
int r; int r;
if (streq_ptr(d->sysfs, sysfs)) assert(sysfs);
if (path_equal(d->sysfs, sysfs))
return 0; return 0;
Hashmap **devices = &u->manager->devices_by_sysfs; Hashmap **devices = &u->manager->devices_by_sysfs;
@ -332,6 +334,20 @@ static void device_catchup(Unit *u) {
Device *d = ASSERT_PTR(DEVICE(u)); Device *d = ASSERT_PTR(DEVICE(u));
/* Second, let's update the state with the enumerated state */ /* Second, let's update the state with the enumerated state */
/* If Device.found (set from Device.deserialized_found) does not have DEVICE_FOUND_UDEV, and the
* device has not been processed by udevd while enumeration, it indicates the unit was never active
* before reexecution, hence we can safely drop the flag from Device.enumerated_found. The device
* will be set up later when udev finishes processing (see also comment in
* device_setup_devlink_unit_one()).
*
* NB: 💣💣💣 If Device.found already contains udev, i.e. the unit was fully ready before
* reexecution, do not unset the flag. Otherwise, e.g. if systemd-udev-trigger.service is started
* just before reexec, reload, and so on, devices being reprocessed (carrying ID_PROCESSING=1
* property) on enumeration and will enter dead state. See issue #35329. */
if (!FLAGS_SET(d->found, DEVICE_FOUND_UDEV) && !d->processed)
d->enumerated_found &= ~DEVICE_FOUND_UDEV;
device_update_found_one(d, d->enumerated_found, _DEVICE_FOUND_MASK); device_update_found_one(d, d->enumerated_found, _DEVICE_FOUND_MASK);
} }
@ -777,8 +793,16 @@ static int device_setup_devlink_unit_one(Manager *m, const char *devlink, Set **
assert(ready_units); assert(ready_units);
assert(not_ready_units); assert(not_ready_units);
if (sd_device_new_from_devname(&dev, devlink) >= 0 && device_is_ready(dev)) if (sd_device_new_from_devname(&dev, devlink) >= 0 && device_is_ready(dev)) {
if (MANAGER_IS_RUNNING(m) && device_is_processed(dev) <= 0)
/* The device is being processed by udevd. We will receive relevant uevent for the
* device later when completed. Let's ignore the device now. */
return 0;
/* Note, even if the device is being processed by udevd, setup the unit on enumerate.
* See also the comments in device_catchup(). */
return device_setup_unit(m, dev, devlink, /* main = */ false, ready_units); return device_setup_unit(m, dev, devlink, /* main = */ false, ready_units);
}
/* the devlink is already removed or not ready */ /* the devlink is already removed or not ready */
if (device_by_path(m, devlink, &u) < 0) if (device_by_path(m, devlink, &u) < 0)
@ -874,14 +898,15 @@ static int device_setup_extra_units(Manager *m, sd_device *dev, Set **ready_unit
return 0; return 0;
} }
static int device_setup_units(Manager *m, sd_device *dev, Set **ready_units, Set **not_ready_units) { static int device_setup_units(Manager *m, sd_device *dev, Set **ret_ready_units, Set **ret_not_ready_units) {
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
const char *syspath, *devname = NULL; const char *syspath, *devname = NULL;
int r; int r;
assert(m); assert(m);
assert(dev); assert(dev);
assert(ready_units); assert(ret_ready_units);
assert(not_ready_units); assert(ret_not_ready_units);
r = sd_device_get_syspath(dev, &syspath); r = sd_device_get_syspath(dev, &syspath);
if (r < 0) if (r < 0)
@ -901,13 +926,13 @@ static int device_setup_units(Manager *m, sd_device *dev, Set **ready_units, Set
/* Add the main unit named after the syspath. If this one fails, don't bother with the rest, /* Add the main unit named after the syspath. If this one fails, don't bother with the rest,
* as this one shall be the main device unit the others just follow. (Compare with how * as this one shall be the main device unit the others just follow. (Compare with how
* device_following() is implemented, see below, which looks for the sysfs device.) */ * device_following() is implemented, see below, which looks for the sysfs device.) */
r = device_setup_unit(m, dev, syspath, /* main = */ true, ready_units); r = device_setup_unit(m, dev, syspath, /* main = */ true, &ready_units);
if (r < 0) if (r < 0)
return r; return r;
/* Add an additional unit for the device node */ /* Add an additional unit for the device node */
if (sd_device_get_devname(dev, &devname) >= 0) if (sd_device_get_devname(dev, &devname) >= 0)
(void) device_setup_unit(m, dev, devname, /* main = */ false, ready_units); (void) device_setup_unit(m, dev, devname, /* main = */ false, &ready_units);
} else { } else {
Unit *u; Unit *u;
@ -915,28 +940,30 @@ static int device_setup_units(Manager *m, sd_device *dev, Set **ready_units, Set
/* If the device exists but not ready, then save the units and unset udev bits later. */ /* If the device exists but not ready, then save the units and unset udev bits later. */
if (device_by_path(m, syspath, &u) >= 0) { if (device_by_path(m, syspath, &u) >= 0) {
r = set_ensure_put(not_ready_units, NULL, DEVICE(u)); r = set_ensure_put(&not_ready_units, NULL, DEVICE(u));
if (r < 0) if (r < 0)
log_unit_debug_errno(u, r, "Failed to store unit, ignoring: %m"); log_unit_debug_errno(u, r, "Failed to store unit, ignoring: %m");
} }
if (sd_device_get_devname(dev, &devname) >= 0 && if (sd_device_get_devname(dev, &devname) >= 0 &&
device_by_path(m, devname, &u) >= 0) { device_by_path(m, devname, &u) >= 0) {
r = set_ensure_put(not_ready_units, NULL, DEVICE(u)); r = set_ensure_put(&not_ready_units, NULL, DEVICE(u));
if (r < 0) if (r < 0)
log_unit_debug_errno(u, r, "Failed to store unit, ignoring: %m"); log_unit_debug_errno(u, r, "Failed to store unit, ignoring: %m");
} }
} }
/* Next, add/update additional .device units point to aliases and symlinks. */ /* Next, add/update additional .device units point to aliases and symlinks. */
(void) device_setup_extra_units(m, dev, ready_units, not_ready_units); (void) device_setup_extra_units(m, dev, &ready_units, &not_ready_units);
/* Safety check: no unit should be in ready_units and not_ready_units simultaneously. */ /* Safety check: no unit should be in ready_units and not_ready_units simultaneously. */
Unit *u; Unit *u;
SET_FOREACH(u, *not_ready_units) SET_FOREACH(u, not_ready_units)
if (set_remove(*ready_units, u)) if (set_remove(ready_units, u))
log_unit_error(u, "Cannot activate and deactivate the unit simultaneously. Deactivating."); log_unit_error(u, "Cannot activate and deactivate the unit simultaneously. Deactivating.");
*ret_ready_units = TAKE_PTR(ready_units);
*ret_not_ready_units = TAKE_PTR(not_ready_units);
return 0; return 0;
} }
@ -1046,13 +1073,32 @@ static void device_enumerate(Manager *m) {
FOREACH_DEVICE(e, dev) { FOREACH_DEVICE(e, dev) {
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL; _cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
const char *syspath;
bool processed;
Device *d; Device *d;
r = sd_device_get_syspath(dev, &syspath);
if (r < 0) {
log_device_debug_errno(dev, r, "Failed to get syspath of enumerated device, ignoring: %m");
continue;
}
r = device_is_processed(dev);
if (r < 0)
log_device_debug_errno(dev, r, "Failed to check if device is processed by udevd, assuming not: %m");
processed = r > 0;
if (device_setup_units(m, dev, &ready_units, &not_ready_units) < 0) if (device_setup_units(m, dev, &ready_units, &not_ready_units) < 0)
continue; continue;
SET_FOREACH(d, ready_units) SET_FOREACH(d, ready_units) {
device_update_found_one(d, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV); device_update_found_one(d, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
/* Why we need to check the syspath here? Because the device unit may be generated by
* a devlink, and the syspath may be different from the one of the original device. */
if (path_equal(d->sysfs, syspath))
d->processed = processed;
}
SET_FOREACH(d, not_ready_units) SET_FOREACH(d, not_ready_units)
device_update_found_one(d, DEVICE_NOT_FOUND, DEVICE_FOUND_UDEV); device_update_found_one(d, DEVICE_NOT_FOUND, DEVICE_FOUND_UDEV);
} }
@ -1097,7 +1143,6 @@ static void device_remove_old_on_move(Manager *m, sd_device *dev) {
} }
static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) { static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
Manager *m = ASSERT_PTR(userdata); Manager *m = ASSERT_PTR(userdata);
sd_device_action_t action; sd_device_action_t action;
const char *sysfs; const char *sysfs;
@ -1150,6 +1195,7 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
* change events */ * change events */
ready = device_is_ready(dev); ready = device_is_ready(dev);
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
(void) device_setup_units(m, dev, &ready_units, &not_ready_units); (void) device_setup_units(m, dev, &ready_units, &not_ready_units);
if (action == SD_DEVICE_REMOVE) { if (action == SD_DEVICE_REMOVE) {

View File

@ -29,7 +29,9 @@ struct Device {
DeviceState state, deserialized_state; DeviceState state, deserialized_state;
DeviceFound found, deserialized_found, enumerated_found; DeviceFound found, deserialized_found, enumerated_found;
bool processed; /* Whether udevd has done processing the device, i.e. the device has database and
* ID_PROCESSING=1 udev property is not set. This is used only by enumeration and
* subsequent catchup process. */
bool bind_mounts; bool bind_mounts;
/* The SYSTEMD_WANTS udev property for this device the last time we saw it */ /* The SYSTEMD_WANTS udev property for this device the last time we saw it */

View File

@ -117,10 +117,9 @@ int exec_context_put_load_credential(ExecContext *c, const char *id, const char
return -ENOMEM; return -ENOMEM;
r = hashmap_ensure_put(&c->load_credentials, &exec_load_credential_hash_ops, lc->id, lc); r = hashmap_ensure_put(&c->load_credentials, &exec_load_credential_hash_ops, lc->id, lc);
if (r < 0) {
assert(r != -EEXIST); assert(r != -EEXIST);
if (r < 0)
return r; return r;
}
TAKE_PTR(lc); TAKE_PTR(lc);
} }
@ -167,10 +166,9 @@ int exec_context_put_set_credential(
return -ENOMEM; return -ENOMEM;
r = hashmap_ensure_put(&c->set_credentials, &exec_set_credential_hash_ops, sc->id, sc); r = hashmap_ensure_put(&c->set_credentials, &exec_set_credential_hash_ops, sc->id, sc);
if (r < 0) {
assert(r != -EEXIST); assert(r != -EEXIST);
if (r < 0)
return r; return r;
}
TAKE_PTR(sc); TAKE_PTR(sc);
} }
@ -193,19 +191,22 @@ int exec_context_put_import_credential(ExecContext *c, const char *glob, const c
*ic = (ExecImportCredential) { *ic = (ExecImportCredential) {
.glob = strdup(glob), .glob = strdup(glob),
.rename = rename ? strdup(rename) : NULL,
}; };
if (!ic->glob || (rename && !ic->rename)) if (!ic->glob)
return -ENOMEM; return -ENOMEM;
if (rename) {
ic->rename = strdup(rename);
if (!ic->rename)
return -ENOMEM;
}
if (ordered_set_contains(c->import_credentials, ic)) if (ordered_set_contains(c->import_credentials, ic))
return 0; return 0;
r = ordered_set_ensure_put(&c->import_credentials, &exec_import_credential_hash_ops, ic); r = ordered_set_ensure_put(&c->import_credentials, &exec_import_credential_hash_ops, ic);
if (r < 0) {
assert(r != -EEXIST); assert(r != -EEXIST);
if (r < 0)
return r; return r;
}
TAKE_PTR(ic); TAKE_PTR(ic);
@ -383,30 +384,46 @@ typedef enum CredentialSearchPath {
_CREDENTIAL_SEARCH_PATH_INVALID = -EINVAL, _CREDENTIAL_SEARCH_PATH_INVALID = -EINVAL,
} CredentialSearchPath; } CredentialSearchPath;
static char** credential_search_path(const ExecParameters *params, CredentialSearchPath path) { static int credential_search_path(const ExecParameters *params, CredentialSearchPath path, char ***ret) {
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
int r;
assert(params); assert(params);
assert(path >= 0 && path < _CREDENTIAL_SEARCH_PATH_MAX); assert(path >= 0 && path < _CREDENTIAL_SEARCH_PATH_MAX);
assert(ret);
/* Assemble a search path to find credentials in. For non-encrypted credentials, We'll look in /* Assemble a search path to find credentials in. For non-encrypted credentials, We'll look in
* /etc/credstore/ (and similar directories in /usr/lib/ + /run/). If we're looking for encrypted * /etc/credstore/ (and similar directories in /usr/lib/ + /run/). If we're looking for encrypted
* credentials, we'll look in /etc/credstore.encrypted/ (and similar dirs). */ * credentials, we'll look in /etc/credstore.encrypted/ (and similar dirs). */
if (IN_SET(path, CREDENTIAL_SEARCH_PATH_ENCRYPTED, CREDENTIAL_SEARCH_PATH_ALL)) { if (IN_SET(path, CREDENTIAL_SEARCH_PATH_ENCRYPTED, CREDENTIAL_SEARCH_PATH_ALL)) {
if (strv_extend(&l, params->received_encrypted_credentials_directory) < 0) r = strv_extend(&l, params->received_encrypted_credentials_directory);
return NULL; if (r < 0)
return r;
if (strv_extend_strv(&l, CONF_PATHS_STRV("credstore.encrypted"), /* filter_duplicates= */ true) < 0) _cleanup_strv_free_ char **add = NULL;
return NULL; r = credential_store_path_encrypted(params->runtime_scope, &add);
if (r < 0)
return r;
r = strv_extend_strv_consume(&l, TAKE_PTR(add), /* filter_duplicates= */ false);
if (r < 0)
return r;
} }
if (IN_SET(path, CREDENTIAL_SEARCH_PATH_TRUSTED, CREDENTIAL_SEARCH_PATH_ALL)) { if (IN_SET(path, CREDENTIAL_SEARCH_PATH_TRUSTED, CREDENTIAL_SEARCH_PATH_ALL)) {
if (strv_extend(&l, params->received_credentials_directory) < 0) r = strv_extend(&l, params->received_credentials_directory);
return NULL; if (r < 0)
return r;
if (strv_extend_strv(&l, CONF_PATHS_STRV("credstore"), /* filter_duplicates= */ true) < 0) _cleanup_strv_free_ char **add = NULL;
return NULL; r = credential_store_path(params->runtime_scope, &add);
if (r < 0)
return r;
r = strv_extend_strv_consume(&l, TAKE_PTR(add), /* filter_duplicates= */ false);
if (r < 0)
return r;
} }
if (DEBUG_LOGGING) { if (DEBUG_LOGGING) {
@ -414,7 +431,8 @@ static char** credential_search_path(const ExecParameters *params, CredentialSea
log_debug("Credential search path is: %s", strempty(t)); log_debug("Credential search path is: %s", strempty(t));
} }
return TAKE_PTR(l); *ret = TAKE_PTR(l);
return 0;
} }
struct load_cred_args { struct load_cred_args {
@ -445,6 +463,10 @@ static int maybe_decrypt_and_write_credential(
assert(data || size == 0); assert(data || size == 0);
if (args->encrypted) { if (args->encrypted) {
switch (args->params->runtime_scope) {
case RUNTIME_SCOPE_SYSTEM:
/* In system mode talk directly to the TPM */
r = decrypt_credential_and_warn( r = decrypt_credential_and_warn(
id, id,
now(CLOCK_REALTIME), now(CLOCK_REALTIME),
@ -454,6 +476,25 @@ static int maybe_decrypt_and_write_credential(
&IOVEC_MAKE(data, size), &IOVEC_MAKE(data, size),
CREDENTIAL_ANY_SCOPE, CREDENTIAL_ANY_SCOPE,
&plaintext); &plaintext);
break;
case RUNTIME_SCOPE_USER:
/* In per user mode we'll not have access to the machine secret, nor to the TPM (most
* likely), hence go via the IPC service instead. Do this if we are run in root's
* per-user invocation too, to minimize differences and because isolating this logic
* into a separate process is generally a good thing anyway. */
r = ipc_decrypt_credential(
id,
now(CLOCK_REALTIME),
getuid(),
&IOVEC_MAKE(data, size),
/* flags= */ 0, /* only allow user creds in user scope */
&plaintext);
break;
default:
assert_not_reached();
}
if (r < 0) if (r < 0)
return r; return r;
@ -611,9 +652,9 @@ static int load_credential(
* directory we received ourselves. We don't support the AF_UNIX stuff in this mode, since we * directory we received ourselves. We don't support the AF_UNIX stuff in this mode, since we
* are operating on a credential store, i.e. this is guaranteed to be regular files. */ * are operating on a credential store, i.e. this is guaranteed to be regular files. */
search_path = credential_search_path(args->params, CREDENTIAL_SEARCH_PATH_ALL); r = credential_search_path(args->params, CREDENTIAL_SEARCH_PATH_ALL, &search_path);
if (!search_path) if (r < 0)
return -ENOMEM; return r;
missing_ok = true; missing_ok = true;
} else } else
@ -797,9 +838,9 @@ static int acquire_credentials(
ORDERED_SET_FOREACH(ic, context->import_credentials) { ORDERED_SET_FOREACH(ic, context->import_credentials) {
_cleanup_free_ char **search_path = NULL; _cleanup_free_ char **search_path = NULL;
search_path = credential_search_path(params, CREDENTIAL_SEARCH_PATH_TRUSTED); r = credential_search_path(params, CREDENTIAL_SEARCH_PATH_TRUSTED, &search_path);
if (!search_path) if (r < 0)
return -ENOMEM; return r;
args.encrypted = false; args.encrypted = false;
@ -811,9 +852,10 @@ static int acquire_credentials(
return r; return r;
search_path = strv_free(search_path); search_path = strv_free(search_path);
search_path = credential_search_path(params, CREDENTIAL_SEARCH_PATH_ENCRYPTED);
if (!search_path) r = credential_search_path(params, CREDENTIAL_SEARCH_PATH_ENCRYPTED, &search_path);
return -ENOMEM; if (r < 0)
return r;
args.encrypted = true; args.encrypted = true;

View File

@ -3,9 +3,11 @@
#include <unistd.h> #include <unistd.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "bitfield.h"
#include "creds-util.h" #include "creds-util.h"
#include "dropin.h" #include "dropin.h"
#include "errno-util.h" #include "errno-util.h"
#include "extract-word.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "generator.h" #include "generator.h"
@ -27,6 +29,7 @@ static char **arg_wants = NULL;
static bool arg_debug_shell = false; static bool arg_debug_shell = false;
static char *arg_debug_tty = NULL; static char *arg_debug_tty = NULL;
static char *arg_default_debug_tty = NULL; static char *arg_default_debug_tty = NULL;
static uint32_t arg_breakpoints = 0;
STATIC_DESTRUCTOR_REGISTER(arg_default_unit, freep); STATIC_DESTRUCTOR_REGISTER(arg_default_unit, freep);
STATIC_DESTRUCTOR_REGISTER(arg_mask, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_mask, strv_freep);
@ -34,6 +37,91 @@ STATIC_DESTRUCTOR_REGISTER(arg_wants, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_debug_tty, freep); STATIC_DESTRUCTOR_REGISTER(arg_debug_tty, freep);
STATIC_DESTRUCTOR_REGISTER(arg_default_debug_tty, freep); STATIC_DESTRUCTOR_REGISTER(arg_default_debug_tty, freep);
typedef enum BreakpointType {
BREAKPOINT_PRE_UDEV,
BREAKPOINT_PRE_BASIC,
BREAKPOINT_PRE_SYSROOT_MOUNT,
BREAKPOINT_PRE_SWITCH_ROOT,
_BREAKPOINT_TYPE_MAX,
_BREAKPOINT_TYPE_INVALID = -EINVAL,
} BreakpointType;
typedef enum BreakpointValidity {
BREAKPOINT_DEFAULT = 1 << 0,
BREAKPOINT_IN_INITRD = 1 << 1,
BREAKPOINT_ON_HOST = 1 << 2,
} BreakpointValidity;
typedef struct BreakpointInfo {
BreakpointType type;
const char *name;
const char *unit;
BreakpointValidity validity;
} BreakpointInfo;
static const struct BreakpointInfo breakpoint_info_table[_BREAKPOINT_TYPE_MAX] = {
{ BREAKPOINT_PRE_UDEV, "pre-udev", "breakpoint-pre-udev.service", BREAKPOINT_IN_INITRD | BREAKPOINT_ON_HOST },
{ BREAKPOINT_PRE_BASIC, "pre-basic", "breakpoint-pre-basic.service", BREAKPOINT_IN_INITRD | BREAKPOINT_ON_HOST },
{ BREAKPOINT_PRE_SYSROOT_MOUNT, "pre-mount", "breakpoint-pre-mount.service", BREAKPOINT_IN_INITRD },
{ BREAKPOINT_PRE_SWITCH_ROOT, "pre-switch-root", "breakpoint-pre-switch-root.service", BREAKPOINT_IN_INITRD | BREAKPOINT_DEFAULT },
};
static BreakpointType parse_breakpoint_from_string_one(const char *s) {
assert(s);
FOREACH_ARRAY(i, breakpoint_info_table, ELEMENTSOF(breakpoint_info_table))
if (streq(i->name, s))
return i->type;
return _BREAKPOINT_TYPE_INVALID;
}
static int parse_breakpoint_from_string(const char *s, uint32_t *ret_breakpoints) {
uint32_t breakpoints = 0;
int r;
assert(ret_breakpoints);
/* Empty value? set default breakpoint */
if (isempty(s)) {
if (in_initrd()) {
FOREACH_ARRAY(i, breakpoint_info_table, ELEMENTSOF(breakpoint_info_table))
if (i->validity & BREAKPOINT_DEFAULT) {
breakpoints |= 1 << i->type;
break;
}
} else
log_warning("No default breakpoint defined on the host, ignoring breakpoint request from kernel command line.");
} else
for (;;) {
_cleanup_free_ char *t = NULL;
BreakpointType tt;
r = extract_first_word(&s, &t, ",", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return r;
if (r == 0)
break;
tt = parse_breakpoint_from_string_one(t);
if (tt < 0) {
log_warning("Invalid breakpoint value '%s', ignoring.", t);
continue;
}
if (in_initrd() && !FLAGS_SET(breakpoint_info_table[tt].validity, BREAKPOINT_IN_INITRD))
log_warning("Breakpoint '%s' not valid in the initrd, ignoring.", t);
else if (!in_initrd() && !FLAGS_SET(breakpoint_info_table[tt].validity, BREAKPOINT_ON_HOST))
log_warning("Breakpoint '%s' not valid on the host, ignoring.", t);
else
breakpoints |= 1 << tt;
}
*ret_breakpoints = breakpoints;
return 0;
}
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
int r; int r;
@ -88,6 +176,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
return free_and_strdup_warn(&arg_default_unit, value); return free_and_strdup_warn(&arg_default_unit, value);
} else if (streq(key, "systemd.break")) {
uint32_t breakpoints = 0;
r = parse_breakpoint_from_string(value, &breakpoints);
if (r < 0)
return log_warning_errno(r, "Failed to parse breakpoint value '%s': %m", value);
arg_breakpoints |= breakpoints;
} else if (!value) { } else if (!value) {
const char *target; const char *target;
@ -269,6 +366,10 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
RET_GATHER(r, install_debug_shell_dropin()); RET_GATHER(r, install_debug_shell_dropin());
} }
BIT_FOREACH(i, arg_breakpoints)
if (strv_extend(&arg_wants, breakpoint_info_table[i].unit) < 0)
return log_oom();
if (get_credentials_dir(&credentials_dir) >= 0) if (get_credentials_dir(&credentials_dir) >= 0)
RET_GATHER(r, process_unit_credentials(credentials_dir)); RET_GATHER(r, process_unit_credentials(credentials_dir));

View File

@ -61,7 +61,7 @@ static void get_chid(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIE
ret_chid->Data4[0] = (ret_chid->Data4[0] & UINT8_C(0x3f)) | UINT8_C(0x80); ret_chid->Data4[0] = (ret_chid->Data4[0] & UINT8_C(0x3f)) | UINT8_C(0x80);
} }
static const uint32_t chid_smbios_table[CHID_TYPES_MAX] = { const uint32_t chid_smbios_table[CHID_TYPES_MAX] = {
[3] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | [3] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY) | (UINT32_C(1) << CHID_SMBIOS_FAMILY) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |

View File

@ -23,5 +23,7 @@ typedef enum ChidSmbiosFields {
_CHID_SMBIOS_FIELDS_MAX, _CHID_SMBIOS_FIELDS_MAX,
} ChidSmbiosFields; } ChidSmbiosFields;
extern const uint32_t chid_smbios_table[CHID_TYPES_MAX];
/* CHID (also called HWID by fwupd) is described at https://github.com/fwupd/fwupd/blob/main/docs/hwids.md */ /* CHID (also called HWID by fwupd) is described at https://github.com/fwupd/fwupd/blob/main/docs/hwids.md */
void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]); void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]);

View File

@ -132,6 +132,7 @@ static int client_context_new(Server *s, pid_t pid, ClientContext **ret) {
.log_level_max = -1, .log_level_max = -1,
.log_ratelimit_interval = s->ratelimit_interval, .log_ratelimit_interval = s->ratelimit_interval,
.log_ratelimit_burst = s->ratelimit_burst, .log_ratelimit_burst = s->ratelimit_burst,
.capability_quintet = CAPABILITY_QUINTET_NULL,
}; };
r = hashmap_ensure_put(&s->client_contexts, NULL, PID_TO_PTR(pid), c); r = hashmap_ensure_put(&s->client_contexts, NULL, PID_TO_PTR(pid), c);
@ -154,7 +155,6 @@ static void client_context_reset(Server *s, ClientContext *c) {
c->comm = mfree(c->comm); c->comm = mfree(c->comm);
c->exe = mfree(c->exe); c->exe = mfree(c->exe);
c->cmdline = mfree(c->cmdline); c->cmdline = mfree(c->cmdline);
c->capeff = mfree(c->capeff);
c->auditid = AUDIT_SESSION_INVALID; c->auditid = AUDIT_SESSION_INVALID;
c->loginuid = UID_INVALID; c->loginuid = UID_INVALID;
@ -184,6 +184,8 @@ static void client_context_reset(Server *s, ClientContext *c) {
c->log_filter_allowed_patterns = set_free_free(c->log_filter_allowed_patterns); c->log_filter_allowed_patterns = set_free_free(c->log_filter_allowed_patterns);
c->log_filter_denied_patterns = set_free_free(c->log_filter_denied_patterns); c->log_filter_denied_patterns = set_free_free(c->log_filter_denied_patterns);
c->capability_quintet = CAPABILITY_QUINTET_NULL;
} }
static ClientContext* client_context_free(Server *s, ClientContext *c) { static ClientContext* client_context_free(Server *s, ClientContext *c) {
@ -233,8 +235,7 @@ static void client_context_read_basic(ClientContext *c) {
if (pid_get_cmdline(c->pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &t) >= 0) if (pid_get_cmdline(c->pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &t) >= 0)
free_and_replace(c->cmdline, t); free_and_replace(c->cmdline, t);
if (get_process_capeff(c->pid, &t) >= 0) (void) pidref_get_capability(&PIDREF_MAKE_FROM_PID(c->pid), &c->capability_quintet);
free_and_replace(c->capeff, t);
} }
static int client_context_read_label( static int client_context_read_label(

View File

@ -7,6 +7,7 @@
#include "sd-id128.h" #include "sd-id128.h"
#include "capability-util.h"
#include "set.h" #include "set.h"
#include "time-util.h" #include "time-util.h"
@ -27,7 +28,7 @@ struct ClientContext {
char *comm; char *comm;
char *exe; char *exe;
char *cmdline; char *cmdline;
char *capeff; CapabilityQuintet capability_quintet;
uint32_t auditid; uint32_t auditid;
uid_t loginuid; uid_t loginuid;

View File

@ -1109,7 +1109,7 @@ static void server_dispatch_message_real(
* Let's use a heap allocation for this one. */ * Let's use a heap allocation for this one. */
cmdline1 = set_iovec_string_field(iovec, &n, "_CMDLINE=", c->cmdline); cmdline1 = set_iovec_string_field(iovec, &n, "_CMDLINE=", c->cmdline);
IOVEC_ADD_STRING_FIELD(iovec, n, c->capeff, "_CAP_EFFECTIVE"); /* Read from /proc/.../status */ IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->capability_quintet.effective, uint64_t, capability_is_set, "%" PRIx64, "_CAP_EFFECTIVE");
IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT"); IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "_AUDIT_SESSION"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "_AUDIT_SESSION");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->loginuid, uid_t, uid_is_valid, UID_FMT, "_AUDIT_LOGINUID"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->loginuid, uid_t, uid_is_valid, UID_FMT, "_AUDIT_LOGINUID");
@ -1144,7 +1144,7 @@ static void server_dispatch_message_real(
if (o->cmdline) if (o->cmdline)
cmdline2 = set_iovec_string_field(iovec, &n, "OBJECT_CMDLINE=", o->cmdline); cmdline2 = set_iovec_string_field(iovec, &n, "OBJECT_CMDLINE=", o->cmdline);
IOVEC_ADD_STRING_FIELD(iovec, n, o->capeff, "OBJECT_CAP_EFFECTIVE"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->capability_quintet.effective, uint64_t, capability_is_set, "%" PRIx64, "OBJECT_CAP_EFFECTIVE");
IOVEC_ADD_SIZED_FIELD(iovec, n, o->label, o->label_size, "OBJECT_SELINUX_CONTEXT"); IOVEC_ADD_SIZED_FIELD(iovec, n, o->label, o->label_size, "OBJECT_SELINUX_CONTEXT");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "OBJECT_AUDIT_SESSION"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "OBJECT_AUDIT_SESSION");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->loginuid, uid_t, uid_is_valid, UID_FMT, "OBJECT_AUDIT_LOGINUID"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->loginuid, uid_t, uid_is_valid, UID_FMT, "OBJECT_AUDIT_LOGINUID");

View File

@ -84,3 +84,19 @@ static inline char** generator_binary_paths(RuntimeScope runtime_scope) {
static inline char** env_generator_binary_paths(RuntimeScope runtime_scope) { static inline char** env_generator_binary_paths(RuntimeScope runtime_scope) {
return generator_binary_paths_internal(runtime_scope, true); return generator_binary_paths_internal(runtime_scope, true);
} }
static inline int credential_store_path(RuntimeScope runtime_scope, char ***ret) {
return sd_path_lookup_strv(
runtime_scope == RUNTIME_SCOPE_SYSTEM ?
SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE : SD_PATH_USER_SEARCH_CREDENTIAL_STORE,
/* suffix= */ NULL,
ret);
}
static inline int credential_store_path_encrypted(RuntimeScope runtime_scope, char ***ret) {
return sd_path_lookup_strv(
runtime_scope == RUNTIME_SCOPE_SYSTEM ?
SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED : SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED,
/* suffix= */ NULL,
ret);
}

View File

@ -36,7 +36,12 @@ static int from_environment(const char *envname, const char *fallback, const cha
return -ENXIO; return -ENXIO;
} }
static int from_home_dir(const char *envname, const char *suffix, char **buffer, const char **ret) { static int from_home_dir(
const char *envname,
const char *suffix,
char **buffer,
const char **ret) {
_cleanup_free_ char *h = NULL; _cleanup_free_ char *h = NULL;
int r; int r;
@ -350,6 +355,30 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
case SD_PATH_SYSTEMD_USER_ENVIRONMENT_GENERATOR: case SD_PATH_SYSTEMD_USER_ENVIRONMENT_GENERATOR:
*ret = USER_ENV_GENERATOR_DIR; *ret = USER_ENV_GENERATOR_DIR;
return 0; return 0;
case SD_PATH_SYSTEM_CREDENTIAL_STORE:
*ret = "/etc/credstore";
return 0;
case SD_PATH_SYSTEM_CREDENTIAL_STORE_ENCRYPTED:
*ret = "/etc/credstore.encrypted";
return 0;
case SD_PATH_USER_CREDENTIAL_STORE:
r = xdg_user_config_dir("credstore", buffer);
if (r < 0)
return r;
*ret = *buffer;
return 0;
case SD_PATH_USER_CREDENTIAL_STORE_ENCRYPTED:
r = xdg_user_config_dir("credstore.encrypted", buffer);
if (r < 0)
return r;
*ret = *buffer;
return 0;
} }
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -366,12 +395,12 @@ static int get_path_alloc(uint64_t type, const char *suffix, char **ret) {
if (r < 0) if (r < 0)
return r; return r;
if (suffix) { if (!isempty(suffix)) {
char *suffixed = path_join(p, suffix); char *suffixed = path_join(p, suffix);
if (!suffixed) if (!suffixed)
return -ENOMEM; return -ENOMEM;
path_simplify(suffixed); path_simplify_full(suffixed, PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
free_and_replace(buffer, suffixed); free_and_replace(buffer, suffixed);
} else if (!buffer) { } else if (!buffer) {
@ -601,8 +630,55 @@ static int get_search(uint64_t type, char ***ret) {
case SD_PATH_SYSTEMD_SEARCH_NETWORK: case SD_PATH_SYSTEMD_SEARCH_NETWORK:
return strv_from_nulstr(ret, NETWORK_DIRS_NULSTR); return strv_from_nulstr(ret, NETWORK_DIRS_NULSTR);
case SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE:
case SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED: {
const char *suffix =
type == SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED ? "credstore.encrypted" : "credstore";
_cleanup_strv_free_ char **l = NULL;
FOREACH_STRING(d, CONF_PATHS("")) {
char *j = path_join(d, suffix);
if (!j)
return -ENOMEM;
r = strv_consume(&l, TAKE_PTR(j));
if (r < 0)
return r;
} }
*ret = TAKE_PTR(l);
return 0;
}
case SD_PATH_USER_SEARCH_CREDENTIAL_STORE:
case SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED: {
const char *suffix =
type == SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED ? "credstore.encrypted" : "credstore";
static const uint64_t dirs[] = {
SD_PATH_USER_CONFIGURATION,
SD_PATH_USER_RUNTIME,
SD_PATH_USER_LIBRARY_PRIVATE,
};
_cleanup_strv_free_ char **l = NULL;
FOREACH_ELEMENT(d, dirs) {
_cleanup_free_ char *p = NULL;
r = sd_path_lookup(*d, suffix, &p);
if (r == -ENXIO)
continue;
if (r < 0)
return r;
r = strv_consume(&l, TAKE_PTR(p));
if (r < 0)
return r;
}
*ret = TAKE_PTR(l);
return 0;
}}
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
@ -637,7 +713,7 @@ _public_ int sd_path_lookup_strv(uint64_t type, const char *suffix, char ***ret)
if (!path_extend(i, suffix)) if (!path_extend(i, suffix))
return -ENOMEM; return -ENOMEM;
path_simplify(*i); path_simplify_full(*i, PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
} }
*ret = TAKE_PTR(l); *ret = TAKE_PTR(l);

View File

@ -1188,35 +1188,29 @@ static int bind_mount(int argc, char *argv[], void *userdata) {
} }
static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
PTYForward ** forward = (PTYForward**) userdata; PTYForward *forward = ASSERT_PTR(userdata);
int r; int r;
assert(m); assert(m);
assert(forward);
if (*forward) { /* Tell the forwarder to exit on the next vhangup(), so that we still flush out what might be queued
/* If the forwarder is already initialized, tell it to * and exit then. */
* exit on the next vhangup(), so that we still flush
* out what might be queued and exit then. */
r = pty_forward_set_ignore_vhangup(*forward, false);
if (r >= 0)
return 0;
r = pty_forward_set_ignore_vhangup(forward, false);
if (r < 0) {
/* On error, quit immediately. */
log_error_errno(r, "Failed to set ignore_vhangup flag: %m"); log_error_errno(r, "Failed to set ignore_vhangup flag: %m");
(void) sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), EXIT_FAILURE);
} }
/* On error, or when the forwarder is not initialized yet, quit immediately */
sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), EXIT_FAILURE);
return 0; return 0;
} }
static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) { static int process_forward(sd_event *event, sd_bus_slot *machine_removed_slot, int master, PTYForwardFlags flags, const char *name) {
char last_char = 0;
bool machine_died;
int r; int r;
assert(event); assert(event);
assert(machine_removed_slot);
assert(master >= 0); assert(master >= 0);
assert(name); assert(name);
@ -1231,24 +1225,21 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, PT
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to enable SIGINT/SITERM handling: %m"); return log_error_errno(r, "Failed to enable SIGINT/SITERM handling: %m");
r = pty_forward_new(event, master, flags, forward); _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
r = pty_forward_new(event, master, flags, &forward);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m"); return log_error_errno(r, "Failed to create PTY forwarder: %m");
/* No userdata should not set previously. */
assert_se(!sd_bus_slot_set_userdata(machine_removed_slot, forward));
r = sd_event_loop(event); r = sd_event_loop(event);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m"); return log_error_errno(r, "Failed to run event loop: %m");
pty_forward_get_last_char(*forward, &last_char); bool machine_died =
machine_died =
(flags & PTY_FORWARD_IGNORE_VHANGUP) && (flags & PTY_FORWARD_IGNORE_VHANGUP) &&
pty_forward_get_ignore_vhangup(*forward) == 0; pty_forward_get_ignore_vhangup(forward) == 0;
*forward = pty_forward_free(*forward);
if (last_char != '\n')
fputc('\n', stdout);
if (!arg_quiet) { if (!arg_quiet) {
if (machine_died) if (machine_died)
@ -1300,7 +1291,6 @@ static int parse_machine_uid(const char *spec, const char **machine, char **uid)
static int login_machine(int argc, char *argv[], void *userdata) { static int login_machine(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
_cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL; _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL;
int master = -1, r; int master = -1, r;
@ -1334,7 +1324,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
"member='MachineRemoved'," "member='MachineRemoved',"
"arg0='", machine, "'"); "arg0='", machine, "'");
r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, &forward); r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, NULL);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to request machine removal match: %m"); return log_error_errno(r, "Failed to request machine removal match: %m");
@ -1346,13 +1336,12 @@ static int login_machine(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return bus_log_parse_error(r); return bus_log_parse_error(r);
return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_VHANGUP, machine); return process_forward(event, slot, master, PTY_FORWARD_IGNORE_VHANGUP, machine);
} }
static int shell_machine(int argc, char *argv[], void *userdata) { static int shell_machine(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
_cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL; _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL;
int master = -1, r; int master = -1, r;
@ -1396,7 +1385,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
"member='MachineRemoved'," "member='MachineRemoved',"
"arg0='", machine, "'"); "arg0='", machine, "'");
r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, &forward); r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, NULL);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to request machine removal match: %m"); return log_error_errno(r, "Failed to request machine removal match: %m");
@ -1426,7 +1415,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return bus_log_parse_error(r); return bus_log_parse_error(r);
return process_forward(event, &forward, master, 0, machine); return process_forward(event, slot, master, /* flags = */ 0, machine);
} }
static int normalize_nspawn_filename(const char *name, char **ret_file) { static int normalize_nspawn_filename(const char *name, char **ret_file) {

View File

@ -252,7 +252,7 @@ static void link_free_engines(Link *link) {
static Link *link_free(Link *link) { static Link *link_free(Link *link) {
assert(link); assert(link);
(void) sysctl_clear_link_shadows(link); (void) link_clear_sysctl_shadows(link);
link_ntp_settings_clear(link); link_ntp_settings_clear(link);
link_dns_settings_clear(link); link_dns_settings_clear(link);

View File

@ -666,7 +666,7 @@ Manager* manager_free(Manager *m) {
if (!m) if (!m)
return NULL; return NULL;
sysctl_remove_monitor(m); manager_remove_sysctl_monitor(m);
free(m->state_file); free(m->state_file);
@ -742,7 +742,7 @@ int manager_start(Manager *m) {
log_debug("Starting..."); log_debug("Starting...");
(void) sysctl_add_monitor(m); (void) manager_install_sysctl_monitor(m);
/* Loading BPF programs requires CAP_SYS_ADMIN and CAP_BPF. /* Loading BPF programs requires CAP_SYS_ADMIN and CAP_BPF.
* Drop the capabilities here, regardless if the load succeeds or not. */ * Drop the capabilities here, regardless if the load succeeds or not. */

View File

@ -56,7 +56,7 @@ static int sysctl_event_handler(void *ctx, void *data, size_t data_sz) {
path = path_join("/proc/sys", we->path); path = path_join("/proc/sys", we->path);
if (!path) { if (!path) {
log_oom(); log_oom_warning();
return 0; return 0;
} }
@ -91,7 +91,7 @@ static int on_ringbuf_io(sd_event_source *s, int fd, uint32_t revents, void *use
return 0; return 0;
} }
int sysctl_add_monitor(Manager *manager) { int manager_install_sysctl_monitor(Manager *manager) {
_cleanup_(sysctl_monitor_bpf_freep) struct sysctl_monitor_bpf *obj = NULL; _cleanup_(sysctl_monitor_bpf_freep) struct sysctl_monitor_bpf *obj = NULL;
_cleanup_(bpf_link_freep) struct bpf_link *sysctl_link = NULL; _cleanup_(bpf_link_freep) struct bpf_link *sysctl_link = NULL;
_cleanup_(bpf_ring_buffer_freep) struct ring_buffer *sysctl_buffer = NULL; _cleanup_(bpf_ring_buffer_freep) struct ring_buffer *sysctl_buffer = NULL;
@ -102,10 +102,10 @@ int sysctl_add_monitor(Manager *manager) {
assert(manager); assert(manager);
r = dlopen_bpf(); r = dlopen_bpf();
if (r < 0) { if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
log_info_errno(r, "sysctl monitor disabled, as BPF support is not available."); return log_debug_errno(r, "sysctl monitor disabled, as BPF support is not available.");
return 0; if (r < 0)
} return log_warning_errno(r, "Failed to load libbpf, not installing sysctl monitor: %m");
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup); r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
if (r < 0) if (r < 0)
@ -113,13 +113,12 @@ int sysctl_add_monitor(Manager *manager) {
root_cgroup_fd = cg_path_open(SYSTEMD_CGROUP_CONTROLLER, "/"); root_cgroup_fd = cg_path_open(SYSTEMD_CGROUP_CONTROLLER, "/");
if (root_cgroup_fd < 0) if (root_cgroup_fd < 0)
return log_warning_errno(root_cgroup_fd, "Failed to open cgroup, ignoring: %m."); return log_warning_errno(root_cgroup_fd, "Failed to open cgroup, ignoring: %m");
obj = sysctl_monitor_bpf__open_and_load(); obj = sysctl_monitor_bpf__open_and_load();
if (!obj) { if (!obj)
log_info_errno(errno, "Unable to load sysctl monitor BPF program, ignoring: %m."); return log_full_errno(errno == EINVAL ? LOG_DEBUG : LOG_INFO, errno,
return 0; "Unable to load sysctl monitor BPF program, ignoring: %m");
}
cgroup_fd = cg_path_open(SYSTEMD_CGROUP_CONTROLLER, cgroup); cgroup_fd = cg_path_open(SYSTEMD_CGROUP_CONTROLLER, cgroup);
if (cgroup_fd < 0) if (cgroup_fd < 0)
@ -130,10 +129,8 @@ int sysctl_add_monitor(Manager *manager) {
sysctl_link = sym_bpf_program__attach_cgroup(obj->progs.sysctl_monitor, root_cgroup_fd); sysctl_link = sym_bpf_program__attach_cgroup(obj->progs.sysctl_monitor, root_cgroup_fd);
r = bpf_get_error_translated(sysctl_link); r = bpf_get_error_translated(sysctl_link);
if (r < 0) { if (r < 0)
log_info_errno(r, "Unable to attach sysctl monitor BPF program to cgroup, ignoring: %m."); return log_warning_errno(r, "Unable to attach sysctl monitor BPF program to cgroup, ignoring: %m");
return 0;
}
fd = sym_bpf_map__fd(obj->maps.written_sysctls); fd = sym_bpf_map__fd(obj->maps.written_sysctls);
if (fd < 0) if (fd < 0)
@ -160,7 +157,7 @@ int sysctl_add_monitor(Manager *manager) {
return 0; return 0;
} }
void sysctl_remove_monitor(Manager *manager) { void manager_remove_sysctl_monitor(Manager *manager) {
assert(manager); assert(manager);
manager->sysctl_event_source = sd_event_source_disable_unref(manager->sysctl_event_source); manager->sysctl_event_source = sd_event_source_disable_unref(manager->sysctl_event_source);
@ -171,7 +168,7 @@ void sysctl_remove_monitor(Manager *manager) {
manager->sysctl_shadow = hashmap_free(manager->sysctl_shadow); manager->sysctl_shadow = hashmap_free(manager->sysctl_shadow);
} }
int sysctl_clear_link_shadows(Link *link) { int link_clear_sysctl_shadows(Link *link) {
_cleanup_free_ char *ipv4 = NULL, *ipv6 = NULL; _cleanup_free_ char *ipv4 = NULL, *ipv6 = NULL;
char *key = NULL, *value = NULL; char *key = NULL, *value = NULL;
@ -188,7 +185,7 @@ int sysctl_clear_link_shadows(Link *link) {
HASHMAP_FOREACH_KEY(value, key, link->manager->sysctl_shadow) HASHMAP_FOREACH_KEY(value, key, link->manager->sysctl_shadow)
if (path_startswith(key, ipv4) || path_startswith(key, ipv6)) { if (path_startswith(key, ipv4) || path_startswith(key, ipv6)) {
assert_se(hashmap_remove_value(link->manager->sysctl_shadow, key, value) == value); assert_se(hashmap_remove_value(link->manager->sysctl_shadow, key, value));
free(key); free(key);
free(value); free(value);
} }

View File

@ -28,13 +28,13 @@ typedef enum IPReversePathFilter {
} IPReversePathFilter; } IPReversePathFilter;
#if HAVE_VMLINUX_H #if HAVE_VMLINUX_H
int sysctl_add_monitor(Manager *manager); int manager_install_sysctl_monitor(Manager *manager);
void sysctl_remove_monitor(Manager *manager); void manager_remove_sysctl_monitor(Manager *manager);
int sysctl_clear_link_shadows(Link *link); int link_clear_sysctl_shadows(Link *link);
#else #else
static inline int sysctl_add_monitor(Manager *manager) { return 0; } static inline int manager_install_sysctl_monitor(Manager *manager) { return 0; }
static inline void sysctl_remove_monitor(Manager *manager) { } static inline void manager_remove_sysctl_monitor(Manager *manager) { }
static inline int sysctl_clear_link_shadows(Link *link) { return 0; } static inline int link_clear_sysctl_shadows(Link *link) { return 0; }
#endif #endif
void manager_set_sysctl(Manager *manager); void manager_set_sysctl(Manager *manager);

View File

@ -475,7 +475,8 @@ int mount_sysfs(const char *dest, MountSettingsMask mount_settings) {
if (!full) if (!full)
return log_oom(); return log_oom();
(void) mkdir(full, 0755); if (mkdir(full, 0755) < 0 && errno != EEXIST)
return log_error_errno(errno, "Failed to create directory '%s': %m", full);
if (FLAGS_SET(mount_settings, MOUNT_APPLY_APIVFS_RO)) if (FLAGS_SET(mount_settings, MOUNT_APPLY_APIVFS_RO))
extra_flags |= MS_RDONLY; extra_flags |= MS_RDONLY;
@ -1405,9 +1406,11 @@ done:
#define NSPAWN_PRIVATE_FULLY_VISIBLE_PROCFS "/run/host/proc" #define NSPAWN_PRIVATE_FULLY_VISIBLE_PROCFS "/run/host/proc"
#define NSPAWN_PRIVATE_FULLY_VISIBLE_SYSFS "/run/host/sys" #define NSPAWN_PRIVATE_FULLY_VISIBLE_SYSFS "/run/host/sys"
int pin_fully_visible_fs(void) { int pin_fully_visible_api_fs(void) {
int r; int r;
log_debug("Pinning fully visible API FS");
(void) mkdir_p(NSPAWN_PRIVATE_FULLY_VISIBLE_PROCFS, 0755); (void) mkdir_p(NSPAWN_PRIVATE_FULLY_VISIBLE_PROCFS, 0755);
(void) mkdir_p(NSPAWN_PRIVATE_FULLY_VISIBLE_SYSFS, 0755); (void) mkdir_p(NSPAWN_PRIVATE_FULLY_VISIBLE_SYSFS, 0755);
@ -1422,7 +1425,7 @@ int pin_fully_visible_fs(void) {
return 0; return 0;
} }
static int do_wipe_fully_visible_fs(void) { static int do_wipe_fully_visible_api_fs(void) {
if (umount2(NSPAWN_PRIVATE_FULLY_VISIBLE_PROCFS, MNT_DETACH) < 0) if (umount2(NSPAWN_PRIVATE_FULLY_VISIBLE_PROCFS, MNT_DETACH) < 0)
return log_error_errno(errno, "Failed to unmount temporary proc: %m"); return log_error_errno(errno, "Failed to unmount temporary proc: %m");
@ -1438,10 +1441,12 @@ static int do_wipe_fully_visible_fs(void) {
return 0; return 0;
} }
int wipe_fully_visible_fs(int mntns_fd) { int wipe_fully_visible_api_fs(int mntns_fd) {
_cleanup_close_ int orig_mntns_fd = -EBADF; _cleanup_close_ int orig_mntns_fd = -EBADF;
int r, rr; int r, rr;
log_debug("Wiping fully visible API FS");
r = namespace_open(0, r = namespace_open(0,
/* ret_pidns_fd = */ NULL, /* ret_pidns_fd = */ NULL,
&orig_mntns_fd, &orig_mntns_fd,
@ -1459,7 +1464,7 @@ int wipe_fully_visible_fs(int mntns_fd) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to enter mount namespace: %m"); return log_error_errno(r, "Failed to enter mount namespace: %m");
rr = do_wipe_fully_visible_fs(); rr = do_wipe_fully_visible_api_fs();
r = namespace_enter(/* pidns_fd = */ -EBADF, r = namespace_enter(/* pidns_fd = */ -EBADF,
orig_mntns_fd, orig_mntns_fd,

View File

@ -73,5 +73,6 @@ int pivot_root_parse(char **pivot_root_new, char **pivot_root_old, const char *s
int setup_pivot_root(const char *directory, const char *pivot_root_new, const char *pivot_root_old); int setup_pivot_root(const char *directory, const char *pivot_root_new, const char *pivot_root_old);
int tmpfs_patch_options(const char *options,uid_t uid_shift, const char *selinux_apifs_context, char **ret); int tmpfs_patch_options(const char *options,uid_t uid_shift, const char *selinux_apifs_context, char **ret);
int pin_fully_visible_fs(void);
int wipe_fully_visible_fs(int mntns_fd); int pin_fully_visible_api_fs(void);
int wipe_fully_visible_api_fs(int mntns_fd);

View File

@ -42,6 +42,7 @@
#include "copy.h" #include "copy.h"
#include "cpu-set-util.h" #include "cpu-set-util.h"
#include "dev-setup.h" #include "dev-setup.h"
#include "devnum-util.h"
#include "discover-image.h" #include "discover-image.h"
#include "dissect-image.h" #include "dissect-image.h"
#include "env-util.h" #include "env-util.h"
@ -1250,7 +1251,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_uid_range = UINT32_C(0x10000); arg_uid_range = UINT32_C(0x10000);
} else if (streq(optarg, "identity")) { } else if (streq(optarg, "identity")) {
/* identity: User namespaces on, UID range is map the 0…0xFFFF range to /* identity: User namespaces on, UID range is map of the 0…0xFFFF range to
* itself, i.e. we don't actually map anything, but do take benefit of * itself, i.e. we don't actually map anything, but do take benefit of
* isolation of capability sets. */ * isolation of capability sets. */
arg_userns_mode = USER_NAMESPACE_FIXED; arg_userns_mode = USER_NAMESPACE_FIXED;
@ -2323,7 +2324,7 @@ static int copy_devnode_one(const char *dest, const char *node, bool ignore_mkno
return log_error_errno(r, "Failed to create '%s': %m", dn); return log_error_errno(r, "Failed to create '%s': %m", dn);
_cleanup_free_ char *sl = NULL; _cleanup_free_ char *sl = NULL;
if (asprintf(&sl, "%s/%u:%u", dn, major(st.st_rdev), minor(st.st_rdev)) < 0) if (asprintf(&sl, "%s/" DEVNUM_FORMAT_STR, dn, DEVNUM_FORMAT_VAL(st.st_rdev)) < 0)
return log_oom(); return log_oom();
_cleanup_free_ char *prefixed = path_join(dest, sl); _cleanup_free_ char *prefixed = path_join(dest, sl);
@ -2847,7 +2848,7 @@ static int reset_audit_loginuid(void) {
if (!arg_privileged) if (!arg_privileged)
return 0; return 0;
r = read_one_line_file("/proc/self/loginuid", &p); r = read_virtual_file("/proc/self/loginuid", SIZE_MAX, &p, /* ret_size= */ NULL);
if (r == -ENOENT) if (r == -ENOENT)
return 0; return 0;
if (r < 0) if (r < 0)
@ -3254,6 +3255,7 @@ static int chase_and_update(char **p, unsigned flags) {
} }
static int determine_uid_shift(const char *directory) { static int determine_uid_shift(const char *directory) {
assert(directory);
if (arg_userns_mode == USER_NAMESPACE_NO) { if (arg_userns_mode == USER_NAMESPACE_NO) {
arg_uid_shift = 0; arg_uid_shift = 0;
@ -3932,7 +3934,7 @@ static int outer_child(
_cleanup_(bind_user_context_freep) BindUserContext *bind_user_context = NULL; _cleanup_(bind_user_context_freep) BindUserContext *bind_user_context = NULL;
_cleanup_strv_free_ char **os_release_pairs = NULL; _cleanup_strv_free_ char **os_release_pairs = NULL;
_cleanup_close_ int fd = -EBADF, mntns_fd = -EBADF; _cleanup_close_ int mntns_fd = -EBADF;
bool idmap = false, enable_fuse; bool idmap = false, enable_fuse;
const char *p; const char *p;
pid_t pid; pid_t pid;
@ -4325,6 +4327,7 @@ static int outer_child(
* visible. Hence there we do it the other way round: we first allocate a new set of namespaces * visible. Hence there we do it the other way round: we first allocate a new set of namespaces
* (and fork for it) for which we then mount sysfs/procfs, and only then switch root. */ * (and fork for it) for which we then mount sysfs/procfs, and only then switch root. */
_cleanup_close_ int notify_fd = -EBADF;
if (arg_privileged) { if (arg_privileged) {
/* Mark everything as shared so our mounts get propagated down. This is required to make new /* Mark everything as shared so our mounts get propagated down. This is required to make new
* bind mounts available in systemd services inside the container that create a new mount * bind mounts available in systemd services inside the container that create a new mount
@ -4355,16 +4358,16 @@ static int outer_child(
* Note, the inner child wouldn't be able to unmount the instances on its own since * Note, the inner child wouldn't be able to unmount the instances on its own since
* it doesn't own the originating mount namespace. IOW, the outer child needs to do * it doesn't own the originating mount namespace. IOW, the outer child needs to do
* this. */ * this. */
r = pin_fully_visible_fs(); r = pin_fully_visible_api_fs();
if (r < 0) if (r < 0)
return r; return r;
} }
fd = setup_notify_child(NULL); notify_fd = setup_notify_child(NULL);
} else } else
fd = setup_notify_child(directory); notify_fd = setup_notify_child(directory);
if (fd < 0) if (notify_fd < 0)
return fd; return notify_fd;
pid = raw_clone(SIGCHLD|CLONE_NEWNS| pid = raw_clone(SIGCHLD|CLONE_NEWNS|
arg_clone_ns_flags | arg_clone_ns_flags |
@ -4429,7 +4432,7 @@ static int outer_child(
return log_error_errno(SYNTHETIC_ERRNO(EIO), return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Short write while sending machine ID."); "Short write while sending machine ID.");
l = send_one_fd(fd_outer_socket, fd, 0); l = send_one_fd(fd_outer_socket, notify_fd, 0);
if (l < 0) if (l < 0)
return log_error_errno(l, "Failed to send notify fd: %m"); return log_error_errno(l, "Failed to send notify fd: %m");
@ -5623,7 +5626,7 @@ static int run_container(
return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Child died too early."); return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Child died too early.");
if (arg_userns_mode != USER_NAMESPACE_NO) { if (arg_userns_mode != USER_NAMESPACE_NO) {
r = wipe_fully_visible_fs(mntns_fd); r = wipe_fully_visible_api_fs(mntns_fd);
if (r < 0) if (r < 0)
return r; return r;
mntns_fd = safe_close(mntns_fd); mntns_fd = safe_close(mntns_fd);
@ -5740,16 +5743,6 @@ static int run_container(
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m"); return log_error_errno(r, "Failed to run event loop: %m");
if (forward) {
char last_char = 0;
(void) pty_forward_get_last_char(forward, &last_char);
forward = pty_forward_free(forward);
if (!arg_quiet && last_char != '\n')
putc('\n', stdout);
}
/* Kill if it is not dead yet anyway */ /* Kill if it is not dead yet anyway */
if (!arg_register && !arg_keep_unit && bus) if (!arg_register && !arg_keep_unit && bus)
terminate_scope(bus, arg_machine); terminate_scope(bus, arg_machine);

View File

@ -14,6 +14,7 @@
#include "main-func.h" #include "main-func.h"
#include "pager.h" #include "pager.h"
#include "pretty-print.h" #include "pretty-print.h"
#include "sort-util.h"
#include "string-util.h" #include "string-util.h"
static const char *arg_suffix = NULL; static const char *arg_suffix = NULL;
@ -101,27 +102,50 @@ static const char* const path_table[_SD_PATH_MAX] = {
[SD_PATH_SYSTEMD_USER_ENVIRONMENT_GENERATOR] = "systemd-user-environment-generator", [SD_PATH_SYSTEMD_USER_ENVIRONMENT_GENERATOR] = "systemd-user-environment-generator",
[SD_PATH_SYSTEMD_SEARCH_SYSTEM_ENVIRONMENT_GENERATOR] = "systemd-search-system-environment-generator", [SD_PATH_SYSTEMD_SEARCH_SYSTEM_ENVIRONMENT_GENERATOR] = "systemd-search-system-environment-generator",
[SD_PATH_SYSTEMD_SEARCH_USER_ENVIRONMENT_GENERATOR] = "systemd-search-user-environment-generator", [SD_PATH_SYSTEMD_SEARCH_USER_ENVIRONMENT_GENERATOR] = "systemd-search-user-environment-generator",
[SD_PATH_SYSTEM_CREDENTIAL_STORE] = "system-credential-store",
[SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE] = "system-search-credential-store",
[SD_PATH_SYSTEM_CREDENTIAL_STORE_ENCRYPTED] = "system-credential-store-encrypted",
[SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED] = "system-search-credential-store-encrypted",
[SD_PATH_USER_CREDENTIAL_STORE] = "user-credential-store",
[SD_PATH_USER_SEARCH_CREDENTIAL_STORE] = "user-search-credential-store",
[SD_PATH_USER_CREDENTIAL_STORE_ENCRYPTED] = "user-credential-store-encrypted",
[SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED] = "user-search-credential-store-encrypted",
}; };
static int order_cmp(const size_t *a, const size_t *b) {
assert(*a < ELEMENTSOF(path_table));
assert(*b < ELEMENTSOF(path_table));
return strcmp(path_table[*a], path_table[*b]);
}
static int list_paths(void) { static int list_paths(void) {
int r = 0; int ret = 0, r;
pager_open(arg_pager_flags); pager_open(arg_pager_flags);
for (size_t i = 0; i < ELEMENTSOF(path_table); i++) { size_t order[ELEMENTSOF(path_table)];
_cleanup_free_ char *p = NULL;
int q;
q = sd_path_lookup(i, arg_suffix, &p); for (size_t i = 0; i < ELEMENTSOF(order); i++)
if (q < 0) { order[i] = i;
log_full_errno(q == -ENXIO ? LOG_DEBUG : LOG_ERR,
q, "Failed to query %s: %m", path_table[i]); typesafe_qsort(order, ELEMENTSOF(order), order_cmp);
if (q != -ENXIO)
RET_GATHER(r, q); for (size_t i = 0; i < ELEMENTSOF(order); i++) {
size_t j = order[i];
const char *t = ASSERT_PTR(path_table[j]);
_cleanup_free_ char *p = NULL;
r = sd_path_lookup(j, arg_suffix, &p);
if (r < 0) {
log_full_errno(r == -ENXIO ? LOG_DEBUG : LOG_ERR, r, "Failed to query %s, proceeding: %m", t);
if (r != -ENXIO)
RET_GATHER(ret, r);
continue; continue;
} }
printf("%s%s:%s %s\n", ansi_highlight(), path_table[i], ansi_normal(), p); printf("%s%s:%s %s\n", ansi_highlight(), t, ansi_normal(), p);
} }
return r; return r;
@ -154,14 +178,16 @@ static int help(void) {
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
printf("%s [OPTIONS...] [NAME...]\n\n" printf("%s [OPTIONS...] [NAME...]\n"
"Show system and user paths.\n\n" "\n%sShow system and user paths.%s\n\n"
" -h --help Show this help\n" " -h --help Show this help\n"
" --version Show package version\n" " --version Show package version\n"
" --suffix=SUFFIX Suffix to append to paths\n" " --suffix=SUFFIX Suffix to append to paths\n"
" --no-pager Do not pipe output into a pager\n" " --no-pager Do not pipe output into a pager\n"
"\nSee the %s for details.\n", "\nSee the %s for details.\n",
program_invocation_short_name, program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link); link);
return 0; return 0;
@ -224,10 +250,11 @@ static int run(int argc, char* argv[]) {
if (r <= 0) if (r <= 0)
return r; return r;
if (argc > optind) if (argc > optind) {
r = 0;
for (int i = optind; i < argc; i++) for (int i = optind; i < argc; i++)
RET_GATHER(r, print_path(argv[i])); RET_GATHER(r, print_path(argv[i]));
else } else
r = list_paths(); r = list_paths();
return r; return r;

View File

@ -10,6 +10,7 @@
#include "resolved-dns-query.h" #include "resolved-dns-query.h"
#include "resolved-dns-synthesize.h" #include "resolved-dns-synthesize.h"
#include "resolved-etc-hosts.h" #include "resolved-etc-hosts.h"
#include "resolved-timeouts.h"
#include "string-util.h" #include "string-util.h"
#define QUERIES_MAX 2048 #define QUERIES_MAX 2048
@ -48,6 +49,8 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) {
assert(c); assert(c);
(void) event_source_disable(c->timeout_event_source);
/* Detach all the DnsTransactions attached to this query */ /* Detach all the DnsTransactions attached to this query */
while ((t = set_steal_first(c->transactions))) { while ((t = set_steal_first(c->transactions))) {
@ -62,6 +65,8 @@ static void dns_query_candidate_abandon(DnsQueryCandidate *c) {
assert(c); assert(c);
(void) event_source_disable(c->timeout_event_source);
/* Abandon all the DnsTransactions attached to this query */ /* Abandon all the DnsTransactions attached to this query */
while ((t = set_steal_first(c->transactions))) { while ((t = set_steal_first(c->transactions))) {
@ -94,6 +99,8 @@ static DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
if (!c) if (!c)
return NULL; return NULL;
c->timeout_event_source = sd_event_source_disable_unref(c->timeout_event_source);
dns_query_candidate_stop(c); dns_query_candidate_stop(c);
dns_query_candidate_unlink(c); dns_query_candidate_unlink(c);
@ -312,6 +319,30 @@ fail:
return r; return r;
} }
static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c);
static int on_candidate_timeout(sd_event_source *s, usec_t usec, void *userdata) {
DnsQueryCandidate *c = userdata;
assert(s);
assert(c);
log_debug("Accepting incomplete query candidate after expedited timeout on partial success.");
dns_query_accept(c->query, c);
return 0;
}
static bool dns_query_candidate_has_partially_succeeded(DnsQueryCandidate *c) {
DnsTransaction *t;
SET_FOREACH(t, c->transactions)
if (t->state == DNS_TRANSACTION_SUCCESS)
return true;
return false;
}
void dns_query_candidate_notify(DnsQueryCandidate *c) { void dns_query_candidate_notify(DnsQueryCandidate *c) {
DnsTransactionState state; DnsTransactionState state;
int r; int r;
@ -323,11 +354,24 @@ void dns_query_candidate_notify(DnsQueryCandidate *c) {
state = dns_query_candidate_state(c); state = dns_query_candidate_state(c);
if (DNS_TRANSACTION_IS_LIVE(state)) if (DNS_TRANSACTION_IS_LIVE(state)) {
if (dns_query_candidate_has_partially_succeeded(c))
(void) event_reset_time_relative(
c->query->manager->event,
&c->timeout_event_source,
CLOCK_BOOTTIME,
CANDIDATE_EXPEDITED_TIMEOUT_USEC, /* accuracy_usec= */ 0,
on_candidate_timeout, c,
/* priority= */ 0, "candidate-timeout",
/* force_reset= */ false);
return; return;
}
if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) { if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
(void) event_source_disable(c->timeout_event_source);
r = dns_query_candidate_next_search_domain(c); r = dns_query_candidate_next_search_domain(c);
if (r < 0) if (r < 0)
goto fail; goto fail;

View File

@ -25,6 +25,7 @@ struct DnsQueryCandidate {
DnsSearchDomain *search_domain; DnsSearchDomain *search_domain;
Set *transactions; Set *transactions;
sd_event_source *timeout_event_source;
LIST_FIELDS(DnsQueryCandidate, candidates_by_query); LIST_FIELDS(DnsQueryCandidate, candidates_by_query);
LIST_FIELDS(DnsQueryCandidate, candidates_by_scope); LIST_FIELDS(DnsQueryCandidate, candidates_by_scope);

View File

@ -16,6 +16,7 @@
#include "resolved-dns-zone.h" #include "resolved-dns-zone.h"
#include "resolved-llmnr.h" #include "resolved-llmnr.h"
#include "resolved-mdns.h" #include "resolved-mdns.h"
#include "resolved-timeouts.h"
#include "socket-util.h" #include "socket-util.h"
#include "strv.h" #include "strv.h"

View File

@ -14,13 +14,10 @@
#include "resolved-dns-transaction.h" #include "resolved-dns-transaction.h"
#include "resolved-dnstls.h" #include "resolved-dnstls.h"
#include "resolved-llmnr.h" #include "resolved-llmnr.h"
#include "resolved-timeouts.h"
#include "string-table.h" #include "string-table.h"
#define TRANSACTIONS_MAX 4096 #define TRANSACTIONS_MAX 4096
#define TRANSACTION_TCP_TIMEOUT_USEC (10U*USEC_PER_SEC)
/* After how much time to repeat classic DNS requests */
#define DNS_TIMEOUT_USEC (SD_RESOLVED_QUERY_TIMEOUT_USEC / DNS_TRANSACTION_ATTEMPTS_MAX)
static void dns_transaction_reset_answer(DnsTransaction *t) { static void dns_transaction_reset_answer(DnsTransaction *t) {
assert(t); assert(t);
@ -1632,13 +1629,10 @@ static usec_t transaction_get_resend_timeout(DnsTransaction *t) {
case DNS_PROTOCOL_DNS: case DNS_PROTOCOL_DNS:
/* When we do TCP, grant a much longer timeout, as in this case there's no need for us to quickly
* resend, as the kernel does that anyway for us, and we really don't want to interrupt it in that
* needlessly. */
if (t->stream) if (t->stream)
return TRANSACTION_TCP_TIMEOUT_USEC; return TRANSACTION_TCP_TIMEOUT_USEC;
return DNS_TIMEOUT_USEC; return TRANSACTION_UDP_TIMEOUT_USEC;
case DNS_PROTOCOL_MDNS: case DNS_PROTOCOL_MDNS:
if (t->probing) if (t->probing)

View File

@ -203,24 +203,3 @@ DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;
const char* dns_transaction_source_to_string(DnsTransactionSource p) _const_; const char* dns_transaction_source_to_string(DnsTransactionSource p) _const_;
DnsTransactionSource dns_transaction_source_from_string(const char *s) _pure_; DnsTransactionSource dns_transaction_source_from_string(const char *s) _pure_;
/* LLMNR Jitter interval, see RFC 4795 Section 7 */
#define LLMNR_JITTER_INTERVAL_USEC (100 * USEC_PER_MSEC)
/* mDNS probing interval, see RFC 6762 Section 8.1 */
#define MDNS_PROBING_INTERVAL_USEC (250 * USEC_PER_MSEC)
/* Maximum attempts to send DNS requests, across all DNS servers */
#define DNS_TRANSACTION_ATTEMPTS_MAX 24
/* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */
#define LLMNR_TRANSACTION_ATTEMPTS_MAX 3
/* Maximum attempts to send MDNS requests, see RFC 6762 Section 8.1 */
#define MDNS_TRANSACTION_ATTEMPTS_MAX 3
#define TRANSACTION_ATTEMPTS_MAX(p) ((p) == DNS_PROTOCOL_LLMNR ? \
LLMNR_TRANSACTION_ATTEMPTS_MAX : \
(p) == DNS_PROTOCOL_MDNS ? \
MDNS_TRANSACTION_ATTEMPTS_MAX : \
DNS_TRANSACTION_ATTEMPTS_MAX)

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "time-util.h"
#include "resolved-def.h"
/* LLMNR Jitter interval, see RFC 4795 Section 7 */
#define LLMNR_JITTER_INTERVAL_USEC (100 * USEC_PER_MSEC)
/* mDNS probing interval, see RFC 6762 Section 8.1 */
#define MDNS_PROBING_INTERVAL_USEC (250 * USEC_PER_MSEC)
/* Maximum attempts to send DNS requests, across all DNS servers */
#define DNS_TRANSACTION_ATTEMPTS_MAX 24
/* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */
#define LLMNR_TRANSACTION_ATTEMPTS_MAX 3
/* Maximum attempts to send MDNS requests, see RFC 6762 Section 8.1 */
#define MDNS_TRANSACTION_ATTEMPTS_MAX 3
#define TRANSACTION_ATTEMPTS_MAX(p) (\
(p) == DNS_PROTOCOL_LLMNR ? \
LLMNR_TRANSACTION_ATTEMPTS_MAX : \
(p) == DNS_PROTOCOL_MDNS ? \
MDNS_TRANSACTION_ATTEMPTS_MAX : \
DNS_TRANSACTION_ATTEMPTS_MAX)
/* After how much time to repeat classic DNS requests */
#define TRANSACTION_UDP_TIMEOUT_USEC (SD_RESOLVED_QUERY_TIMEOUT_USEC / DNS_TRANSACTION_ATTEMPTS_MAX)
/* When we do TCP, grant a much longer timeout, as in this case there's no need for us to quickly
* resend, as the kernel does that anyway for us, and we really don't want to interrupt it in that
* needlessly. */
#define TRANSACTION_TCP_TIMEOUT_USEC (10 * USEC_PER_SEC)
/* Should be longer than transaction timeout for a single UDP transaction, so we get at least
* one transaction retry before timeouting the whole candidate */
#define CANDIDATE_EXPEDITED_TIMEOUT_USEC (TRANSACTION_UDP_TIMEOUT_USEC + 1 * USEC_PER_SEC)

View File

@ -1555,16 +1555,9 @@ static int run_context_reconnect(RunContext *c) {
} }
static void run_context_check_done(RunContext *c) { static void run_context_check_done(RunContext *c) {
bool done;
assert(c); assert(c);
done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job; if (STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job)
if (c->forward && !pty_forward_is_done(c->forward) && done) /* If the service is gone, it's time to drain the output */
done = pty_forward_drain(c->forward);
if (done)
(void) sd_event_exit(c->event, EXIT_SUCCESS); (void) sd_event_exit(c->event, EXIT_SUCCESS);
} }
@ -2094,21 +2087,8 @@ static int start_transient_service(sd_bus *bus) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m"); return log_error_errno(r, "Failed to run event loop: %m");
if (c.forward) {
char last_char = 0;
r = pty_forward_get_last_char(c.forward, &last_char);
if (r >= 0 && !arg_quiet && last_char != '\n')
fputc('\n', stdout);
}
if (arg_wait && !arg_quiet) { if (arg_wait && !arg_quiet) {
/* Explicitly destroy the PTY forwarder, so that the PTY device is usable again, with its
* original settings (i.e. proper line breaks), so that we can show the summary in a pretty
* way. */
c.forward = pty_forward_free(c.forward);
if (!isempty(c.result)) if (!isempty(c.result))
log_info("Finished with result: %s", strna(c.result)); log_info("Finished with result: %s", strna(c.result));

View File

@ -21,6 +21,7 @@
#include "battery-util.h" #include "battery-util.h"
#include "blockdev-util.h" #include "blockdev-util.h"
#include "cap-list.h" #include "cap-list.h"
#include "capability-util.h"
#include "cgroup-util.h" #include "cgroup-util.h"
#include "compare-operator.h" #include "compare-operator.h"
#include "condition.h" #include "condition.h"
@ -701,45 +702,23 @@ static int condition_test_security(Condition *c, char **env) {
} }
static int condition_test_capability(Condition *c, char **env) { static int condition_test_capability(Condition *c, char **env) {
unsigned long long capabilities = (unsigned long long) -1; int r;
_cleanup_fclose_ FILE *f = NULL;
int value, r;
assert(c); assert(c);
assert(c->parameter); assert(c->parameter);
assert(c->type == CONDITION_CAPABILITY); assert(c->type == CONDITION_CAPABILITY);
/* If it's an invalid capability, we don't have it */ /* If it's an invalid capability, we don't have it */
value = capability_from_name(c->parameter); int value = capability_from_name(c->parameter);
if (value < 0) if (value < 0)
return -EINVAL; return -EINVAL;
/* If it's a valid capability we default to assume CapabilityQuintet q;
* that we have it */ r = pidref_get_capability(&PIDREF_MAKE_FROM_PID(getpid_cached()), &q);
f = fopen("/proc/self/status", "re");
if (!f)
return -errno;
for (;;) {
_cleanup_free_ char *line = NULL;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0) if (r < 0)
return r; return r;
if (r == 0)
break;
const char *p = startswith(line, "CapBnd:"); return !!(q.bounding & ((UINT64_C(1) << value)));
if (p) {
if (sscanf(p, "%llx", &capabilities) != 1)
return -EIO;
break;
}
}
return !!(capabilities & (1ULL << value));
} }
static int condition_test_needs_update(Condition *c, char **env) { static int condition_test_needs_update(Condition *c, char **env) {

View File

@ -536,6 +536,8 @@ int mount_switch_root_full(const char *path, unsigned long mount_propagation_fla
} }
} }
log_debug("Successfully switched root to '%s'.", path);
/* Finally, let's establish the requested propagation flags. */ /* Finally, let's establish the requested propagation flags. */
if (mount_propagation_flag == 0) if (mount_propagation_flag == 0)
return 0; return 0;
@ -1319,7 +1321,7 @@ int make_userns(uid_t uid_shift, uid_t uid_range, uid_t source_owner, uid_t dest
* process whose only purpose is to give us a new user namespace. It's killed when we got it. */ * process whose only purpose is to give us a new user namespace. It's killed when we got it. */
if (!userns_shift_range_valid(uid_shift, uid_range)) if (!userns_shift_range_valid(uid_shift, uid_range))
return -EINVAL; return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid UID range for user namespace.");
if (IN_SET(idmapping, REMOUNT_IDMAPPING_NONE, REMOUNT_IDMAPPING_HOST_ROOT)) { if (IN_SET(idmapping, REMOUNT_IDMAPPING_NONE, REMOUNT_IDMAPPING_HOST_ROOT)) {
if (asprintf(&line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0u, uid_shift, uid_range) < 0) if (asprintf(&line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0u, uid_shift, uid_range) < 0)

View File

@ -87,6 +87,8 @@ int nsresource_allocate_userns(const char *name, uint64_t size) {
SD_JSON_BUILD_PAIR("userNamespaceFileDescriptor", SD_JSON_BUILD_UNSIGNED(userns_fd_idx))); SD_JSON_BUILD_PAIR("userNamespaceFileDescriptor", SD_JSON_BUILD_UNSIGNED(userns_fd_idx)));
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to call AllocateUserRange() varlink call: %m"); return log_debug_errno(r, "Failed to call AllocateUserRange() varlink call: %m");
if (streq_ptr(error_id, "io.systemd.NamespaceResource.UserNamespaceInterfaceNotSupported"))
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unprivileged user namespace delegation is not supported on this system.");
if (error_id) if (error_id)
return log_debug_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to allocate user namespace with %" PRIu64 " users: %s", size, error_id); return log_debug_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to allocate user namespace with %" PRIu64 " users: %s", size, error_id);

View File

@ -58,8 +58,8 @@ struct PTYForward {
sd_event_source *stdin_event_source; sd_event_source *stdin_event_source;
sd_event_source *stdout_event_source; sd_event_source *stdout_event_source;
sd_event_source *master_event_source; sd_event_source *master_event_source;
sd_event_source *sigwinch_event_source; sd_event_source *sigwinch_event_source;
sd_event_source *exit_event_source;
struct termios saved_stdin_attr; struct termios saved_stdin_attr;
struct termios saved_stdout_attr; struct termios saved_stdout_attr;
@ -81,14 +81,16 @@ struct PTYForward {
bool read_from_master:1; bool read_from_master:1;
bool done:1; bool done:1;
bool drain:1;
bool last_char_set:1; bool last_char_set:1;
char last_char; char last_char;
char last_char_safe;
char in_buffer[LINE_MAX], *out_buffer; char in_buffer[LINE_MAX], *out_buffer;
size_t out_buffer_size; size_t out_buffer_size;
size_t in_buffer_full, out_buffer_full; size_t in_buffer_full, out_buffer_full;
size_t out_buffer_write_len; /* The length of the output in the buffer except for the trailing
* truncated OSC, CSI, or some (but not all) ESC sequence. */
usec_t escape_timestamp; usec_t escape_timestamp;
unsigned escape_counter; unsigned escape_counter;
@ -114,9 +116,9 @@ static void pty_forward_disconnect(PTYForward *f) {
f->stdin_event_source = sd_event_source_unref(f->stdin_event_source); f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
f->stdout_event_source = sd_event_source_unref(f->stdout_event_source); f->stdout_event_source = sd_event_source_unref(f->stdout_event_source);
f->master_event_source = sd_event_source_unref(f->master_event_source); f->master_event_source = sd_event_source_unref(f->master_event_source);
f->sigwinch_event_source = sd_event_source_unref(f->sigwinch_event_source); f->sigwinch_event_source = sd_event_source_unref(f->sigwinch_event_source);
f->exit_event_source = sd_event_source_unref(f->exit_event_source);
f->event = sd_event_unref(f->event); f->event = sd_event_unref(f->event);
if (f->output_fd >= 0) { if (f->output_fd >= 0) {
@ -133,6 +135,19 @@ static void pty_forward_disconnect(PTYForward *f) {
(void) loop_write(f->output_fd, ANSI_WINDOW_TITLE_POP, SIZE_MAX); (void) loop_write(f->output_fd, ANSI_WINDOW_TITLE_POP, SIZE_MAX);
} }
if (f->last_char_set && f->last_char != '\n') {
const char *s;
if (isatty_safe(f->output_fd) && f->last_char != '\r')
s = "\r\n";
else
s = "\n";
(void) loop_write(f->output_fd, s, SIZE_MAX);
f->last_char_set = true;
f->last_char = '\n';
}
if (f->close_output_fd) if (f->close_output_fd)
f->output_fd = safe_close(f->output_fd); f->output_fd = safe_close(f->output_fd);
} }
@ -151,6 +166,7 @@ static void pty_forward_disconnect(PTYForward *f) {
f->out_buffer = mfree(f->out_buffer); f->out_buffer = mfree(f->out_buffer);
f->out_buffer_size = 0; f->out_buffer_size = 0;
f->out_buffer_full = 0; f->out_buffer_full = 0;
f->out_buffer_write_len = 0;
f->in_buffer_full = 0; f->in_buffer_full = 0;
f->csi_sequence = mfree(f->csi_sequence); f->csi_sequence = mfree(f->csi_sequence);
@ -277,6 +293,9 @@ static int insert_background_color(PTYForward *f, size_t offset) {
assert(f); assert(f);
if (FLAGS_SET(f->flags, PTY_FORWARD_DUMB_TERMINAL))
return 0;
if (!f->background_color) if (!f->background_color)
return 0; return 0;
@ -359,6 +378,9 @@ static int is_csi_background_reset_sequence(const char *seq) {
static int insert_background_fix(PTYForward *f, size_t offset) { static int insert_background_fix(PTYForward *f, size_t offset) {
assert(f); assert(f);
if (FLAGS_SET(f->flags, PTY_FORWARD_DUMB_TERMINAL))
return 0;
if (!f->background_color) if (!f->background_color)
return 0; return 0;
@ -391,6 +413,9 @@ bool shall_set_terminal_title(void) {
static int insert_window_title_fix(PTYForward *f, size_t offset) { static int insert_window_title_fix(PTYForward *f, size_t offset) {
assert(f); assert(f);
if (FLAGS_SET(f->flags, PTY_FORWARD_DUMB_TERMINAL))
return 0;
if (!f->title_prefix) if (!f->title_prefix)
return 0; return 0;
@ -414,12 +439,6 @@ static int pty_forward_ansi_process(PTYForward *f, size_t offset) {
assert(f); assert(f);
assert(offset <= f->out_buffer_full); assert(offset <= f->out_buffer_full);
if (!f->background_color && !f->title_prefix)
return 0;
if (FLAGS_SET(f->flags, PTY_FORWARD_DUMB_TERMINAL))
return 0;
for (size_t i = offset; i < f->out_buffer_full; i++) { for (size_t i = offset; i < f->out_buffer_full; i++) {
char c = f->out_buffer[i]; char c = f->out_buffer[i];
@ -433,8 +452,11 @@ static int pty_forward_ansi_process(PTYForward *f, size_t offset) {
if (r < 0) if (r < 0)
return r; return r;
i += r; i += r;
f->last_char_safe = c;
} else if (c == 0x1B) /* ESC */ } else if (c == 0x1B) /* ESC */
f->ansi_color_state = ANSI_COLOR_STATE_ESC; f->ansi_color_state = ANSI_COLOR_STATE_ESC;
else if (!char_is_cc(c))
f->last_char_safe = c;
break; break;
case ANSI_COLOR_STATE_ESC: case ANSI_COLOR_STATE_ESC:
@ -545,6 +567,9 @@ static int pty_forward_ansi_process(PTYForward *f, size_t offset) {
default: default:
assert_not_reached(); assert_not_reached();
} }
if (f->ansi_color_state == ANSI_COLOR_STATE_TEXT)
f->out_buffer_write_len = i + 1;
} }
return 0; return 0;
@ -579,7 +604,7 @@ static int do_shovel(PTYForward *f) {
} }
if (f->out_buffer) { if (f->out_buffer) {
f->out_buffer_full = strlen(f->out_buffer); f->out_buffer_full = f->out_buffer_write_len = strlen(f->out_buffer);
f->out_buffer_size = MALLOC_SIZEOF_SAFE(f->out_buffer); f->out_buffer_size = MALLOC_SIZEOF_SAFE(f->out_buffer);
} }
} }
@ -679,9 +704,10 @@ static int do_shovel(PTYForward *f) {
} }
} }
if (f->stdout_writable && f->out_buffer_full > 0) { if (f->stdout_writable && f->out_buffer_write_len > 0) {
assert(f->out_buffer_write_len <= f->out_buffer_full);
k = write(f->output_fd, f->out_buffer, f->out_buffer_full); k = write(f->output_fd, f->out_buffer, f->out_buffer_write_len);
if (k < 0) { if (k < 0) {
if (errno == EAGAIN) if (errno == EAGAIN)
@ -695,14 +721,22 @@ static int do_shovel(PTYForward *f) {
} else { } else {
if (k > 0) { if (k > 0 && f->last_char_safe != '\0') {
if ((size_t) k == f->out_buffer_write_len)
/* If we wrote all, then save the last safe character. */
f->last_char = f->last_char_safe;
else
/* If we wrote partially, then tentatively save the last written character.
* Hopefully, we will write more in the next loop. */
f->last_char = f->out_buffer[k-1]; f->last_char = f->out_buffer[k-1];
f->last_char_set = true; f->last_char_set = true;
} }
assert(f->out_buffer_full >= (size_t) k); assert(f->out_buffer_write_len >= (size_t) k);
memmove(f->out_buffer, f->out_buffer + k, f->out_buffer_full - k); memmove(f->out_buffer, f->out_buffer + k, f->out_buffer_full - k);
f->out_buffer_full -= k; f->out_buffer_full -= k;
f->out_buffer_write_len -= k;
} }
} }
} }
@ -711,16 +745,11 @@ static int do_shovel(PTYForward *f) {
/* Exit the loop if any side hung up and if there's /* Exit the loop if any side hung up and if there's
* nothing more to write or nothing we could write. */ * nothing more to write or nothing we could write. */
if ((f->out_buffer_full <= 0 || f->stdout_hangup) && if ((f->out_buffer_write_len <= 0 || f->stdout_hangup) &&
(f->in_buffer_full <= 0 || f->master_hangup)) (f->in_buffer_full <= 0 || f->master_hangup))
return pty_forward_done(f, 0); return pty_forward_done(f, 0);
} }
/* If we were asked to drain, and there's nothing more to handle from the master, then call the callback
* too. */
if (f->drain && drained(f))
return pty_forward_done(f, 0);
return 0; return 0;
} }
@ -795,6 +824,40 @@ static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo *
return 0; return 0;
} }
static int on_exit_event(sd_event_source *e, void *userdata) {
PTYForward *f = ASSERT_PTR(userdata);
int r;
assert(e);
assert(e == f->exit_event_source);
/* Drain the buffer on exit. */
if (f->done)
return 0;
for (unsigned trial = 0; trial < 1000; trial++) {
if (drained(f))
return pty_forward_done(f, 0);
if (!f->master_hangup)
f->master_writable = f->master_readable = true;
if (!f->stdin_hangup)
f->stdin_readable = true;
if (!f->stdout_hangup)
f->stdout_writable = true;
r = shovel(f);
if (r < 0)
return r;
if (f->done)
return 0;
}
/* If we could not drain, then propagate recognizable error code. */
return pty_forward_done(f, -ELOOP);
}
int pty_forward_new( int pty_forward_new(
sd_event *event, sd_event *event,
int master, int master,
@ -955,6 +1018,12 @@ int pty_forward_new(
(void) sd_event_source_set_description(f->sigwinch_event_source, "ptyfwd-sigwinch"); (void) sd_event_source_set_description(f->sigwinch_event_source, "ptyfwd-sigwinch");
r = sd_event_add_exit(f->event, &f->exit_event_source, on_exit_event, f);
if (r < 0)
return r;
(void) sd_event_source_set_description(f->exit_event_source, "ptyfwd-exit");
*ret = TAKE_PTR(f); *ret = TAKE_PTR(f);
return 0; return 0;
@ -972,17 +1041,6 @@ PTYForward *pty_forward_free(PTYForward *f) {
return mfree(f); return mfree(f);
} }
int pty_forward_get_last_char(PTYForward *f, char *ch) {
assert(f);
assert(ch);
if (!f->last_char_set)
return -ENXIO;
*ch = f->last_char;
return 0;
}
int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) { int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) {
int r; int r;
@ -1012,12 +1070,6 @@ bool pty_forward_get_ignore_vhangup(PTYForward *f) {
return FLAGS_SET(f->flags, PTY_FORWARD_IGNORE_VHANGUP); return FLAGS_SET(f->flags, PTY_FORWARD_IGNORE_VHANGUP);
} }
bool pty_forward_is_done(PTYForward *f) {
assert(f);
return f->done;
}
void pty_forward_set_handler(PTYForward *f, PTYForwardHandler cb, void *userdata) { void pty_forward_set_handler(PTYForward *f, PTYForwardHandler cb, void *userdata) {
assert(f); assert(f);
@ -1025,20 +1077,6 @@ void pty_forward_set_handler(PTYForward *f, PTYForwardHandler cb, void *userdata
f->userdata = userdata; f->userdata = userdata;
} }
bool pty_forward_drain(PTYForward *f) {
assert(f);
/* Starts draining the forwarder. Specifically:
*
* - Returns true if there are no unprocessed bytes from the pty, false otherwise
*
* - Makes sure the handler function is called the next time the number of unprocessed bytes hits zero
*/
f->drain = true;
return drained(f);
}
int pty_forward_set_priority(PTYForward *f, int64_t priority) { int pty_forward_set_priority(PTYForward *f, int64_t priority) {
int r; int r;

View File

@ -25,20 +25,14 @@ typedef enum PTYForwardFlags {
typedef int (*PTYForwardHandler)(PTYForward *f, int rcode, void *userdata); typedef int (*PTYForwardHandler)(PTYForward *f, int rcode, void *userdata);
int pty_forward_new(sd_event *event, int master, PTYForwardFlags flags, PTYForward **f); int pty_forward_new(sd_event *event, int master, PTYForwardFlags flags, PTYForward **ret);
PTYForward* pty_forward_free(PTYForward *f); PTYForward* pty_forward_free(PTYForward *f);
int pty_forward_get_last_char(PTYForward *f, char *ch);
int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup); int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup);
bool pty_forward_get_ignore_vhangup(PTYForward *f); bool pty_forward_get_ignore_vhangup(PTYForward *f);
bool pty_forward_is_done(PTYForward *f);
void pty_forward_set_handler(PTYForward *f, PTYForwardHandler handler, void *userdata); void pty_forward_set_handler(PTYForward *f, PTYForwardHandler handler, void *userdata);
bool pty_forward_drain(PTYForward *f);
int pty_forward_set_priority(PTYForward *f, int64_t priority); int pty_forward_set_priority(PTYForward *f, int64_t priority);
int pty_forward_set_width_height(PTYForward *f, unsigned width, unsigned height); int pty_forward_set_width_height(PTYForward *f, unsigned width, unsigned height);

View File

@ -120,6 +120,16 @@ enum {
SD_PATH_USER_STATE_PRIVATE, SD_PATH_USER_STATE_PRIVATE,
/* credential store */
SD_PATH_SYSTEM_CREDENTIAL_STORE,
SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE,
SD_PATH_SYSTEM_CREDENTIAL_STORE_ENCRYPTED,
SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED,
SD_PATH_USER_CREDENTIAL_STORE,
SD_PATH_USER_SEARCH_CREDENTIAL_STORE,
SD_PATH_USER_CREDENTIAL_STORE_ENCRYPTED,
SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED,
_SD_PATH_MAX _SD_PATH_MAX
}; };

View File

@ -596,7 +596,7 @@ int transfer_read_definition(Transfer *t, const char *path, const char **dirs, H
!IN_SET(t->target.type, RESOURCE_DIRECTORY, RESOURCE_SUBVOLUME))) !IN_SET(t->target.type, RESOURCE_DIRECTORY, RESOURCE_SUBVOLUME)))
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL), return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
"Target type '%s' is incompatible with source type '%s', refusing.", "Target type '%s' is incompatible with source type '%s', refusing.",
resource_type_to_string(t->source.type), resource_type_to_string(t->target.type)); resource_type_to_string(t->target.type), resource_type_to_string(t->source.type));
if (!t->source.path && !t->source.path_auto) if (!t->source.path && !t->source.path_auto)
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL), return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),

View File

@ -305,6 +305,18 @@ static void test_capability_get_ambient(void) {
} }
} }
static void test_pidref_get_capability(void) {
CapabilityQuintet q = CAPABILITY_QUINTET_NULL;
assert_se(pidref_get_capability(&PIDREF_MAKE_FROM_PID(getpid_cached()), &q) >= 0);
assert_se(q.effective != CAP_MASK_UNSET);
assert_se(q.inheritable != CAP_MASK_UNSET);
assert_se(q.permitted != CAP_MASK_UNSET);
assert_se(q.effective != CAP_MASK_UNSET);
assert_se(q.ambient != CAP_MASK_UNSET);
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
bool run_ambient; bool run_ambient;
@ -336,5 +348,7 @@ int main(int argc, char *argv[]) {
test_capability_get_ambient(); test_capability_get_ambient();
test_pidref_get_capability();
return 0; return 0;
} }

View File

@ -1398,6 +1398,10 @@ static void run_tests(RuntimeScope scope, char **patterns) {
ASSERT_NOT_NULL(unit_paths = strjoin(PRIVATE_UNIT_DIR, ":", user_runtime_unit_dir)); ASSERT_NOT_NULL(unit_paths = strjoin(PRIVATE_UNIT_DIR, ":", user_runtime_unit_dir));
ASSERT_OK(setenv_unit_path(unit_paths)); ASSERT_OK(setenv_unit_path(unit_paths));
/* Write credential for test-execute-load-credential to the fake runtime dir, too */
_cleanup_free_ char *j = ASSERT_PTR(path_join(runtime_dir, "credstore/test-execute.load-credential"));
ASSERT_OK(write_string_file(j, "foo", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755));
r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m); r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
if (manager_errno_skip_test(r)) if (manager_errno_skip_test(r))
return (void) log_tests_skipped_errno(r, "manager_new"); return (void) log_tests_skipped_errno(r, "manager_new");

View File

@ -363,24 +363,6 @@ TEST(status_field) {
} }
} }
TEST(capeff) {
for (int pid = 0; pid < 2; pid++) {
_cleanup_free_ char *capeff = NULL;
int r, p;
r = get_process_capeff(0, &capeff);
log_info("capeff: '%s' (r=%d)", capeff, r);
if (IN_SET(r, -ENOENT, -EPERM))
return;
assert_se(r == 0);
assert_se(*capeff);
p = capeff[strspn(capeff, HEXDIGITS)];
assert_se(!p || isspace(p));
}
}
TEST(read_one_line_file) { TEST(read_one_line_file) {
_cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-fileio-1lf-XXXXXX"; _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-fileio-1lf-XXXXXX";
int fd; int fd;

View File

@ -19,6 +19,7 @@ udevadm_sources = files(
libudevd_core_sources = files( libudevd_core_sources = files(
'net/link-config.c', 'net/link-config.c',
'udev-config.c',
'udev-ctrl.c', 'udev-ctrl.c',
'udev-event.c', 'udev-event.c',
'udev-format.c', 'udev-format.c',

View File

@ -650,7 +650,16 @@ static int get_pci_slot_specifiers(
* where the slot makes up the upper 5 bits. */ * where the slot makes up the upper 5 bits. */
func += slot * 8; func += slot * 8;
if (domain > 0 && asprintf(&domain_spec, "P%u", domain) < 0) /* Include the PCI domain in the name if the ID_NET_NAME_INCLUDE_DOMAIN property says so, if it is
* set. If it is not set, include it if the domain is non-zero. */
r = device_get_property_bool(dev, "ID_NET_NAME_INCLUDE_DOMAIN");
if (r < 0) {
if (r != -ENOENT)
log_device_warning_errno(dev, r, "Failed to read property \"ID_NET_NAME_INCLUDE_DOMAIN\", ignoring: %m");
r = domain > 0;
}
if (r > 0 && asprintf(&domain_spec, "P%u", domain) < 0)
return log_oom_debug(); return log_oom_debug();
if (asprintf(&bus_and_slot_spec, "p%us%u", bus, slot) < 0) if (asprintf(&bus_and_slot_spec, "p%us%u", bus, slot) < 0)

View File

@ -42,11 +42,28 @@ void udev_builtin_exit(void) {
(*b)->exit(); (*b)->exit();
} }
bool udev_builtin_should_reload(void) { UdevReloadFlags udev_builtin_should_reload(void) {
UdevReloadFlags flags = 0;
for (UdevBuiltinCommand i = 0; i < _UDEV_BUILTIN_MAX; i++) for (UdevBuiltinCommand i = 0; i < _UDEV_BUILTIN_MAX; i++)
if (builtins[i] && builtins[i]->should_reload && builtins[i]->should_reload()) if (builtins[i] && builtins[i]->should_reload && builtins[i]->should_reload())
return true; flags |= 1u << i;
return false;
if (flags != 0)
flags |= UDEV_RELOAD_KILL_WORKERS;
return flags;
}
void udev_builtin_reload(UdevReloadFlags flags) {
for (UdevBuiltinCommand i = 0; i < _UDEV_BUILTIN_MAX; i++) {
if (!FLAGS_SET(flags, 1u << i) || !builtins[i])
continue;
if (builtins[i]->exit)
builtins[i]->exit();
if (builtins[i]->init)
builtins[i]->init();
}
} }
void udev_builtin_list(void) { void udev_builtin_list(void) {

View File

@ -59,7 +59,8 @@ const char* udev_builtin_name(UdevBuiltinCommand cmd);
bool udev_builtin_run_once(UdevBuiltinCommand cmd); bool udev_builtin_run_once(UdevBuiltinCommand cmd);
int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *command); int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *command);
void udev_builtin_list(void); void udev_builtin_list(void);
bool udev_builtin_should_reload(void); UdevReloadFlags udev_builtin_should_reload(void);
void udev_builtin_reload(UdevReloadFlags flags);
int udev_builtin_add_property(UdevEvent *event, const char *key, const char *val); int udev_builtin_add_property(UdevEvent *event, const char *key, const char *val);
int udev_builtin_add_propertyf(UdevEvent *event, const char *key, const char *valf, ...) _printf_(3, 4); int udev_builtin_add_propertyf(UdevEvent *event, const char *key, const char *valf, ...) _printf_(3, 4);
int udev_builtin_import_property(UdevEvent *event, const char *key); int udev_builtin_import_property(UdevEvent *event, const char *key);

365
src/udev/udev-config.c Normal file
View File

@ -0,0 +1,365 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <getopt.h>
#include <unistd.h>
#include "conf-parser.h"
#include "cpu-set-util.h"
#include "limits-util.h"
#include "parse-util.h"
#include "pretty-print.h"
#include "proc-cmdline.h"
#include "signal-util.h"
#include "syslog-util.h"
#include "udev-config.h"
#include "udev-manager.h"
#include "udev-rules.h"
#include "udev-util.h"
#include "udev-worker.h"
#include "version.h"
#define WORKER_NUM_MAX UINT64_C(2048)
static bool arg_debug = false;
bool arg_daemonize = false;
static DEFINE_CONFIG_PARSE_ENUM(config_parse_resolve_name_timing, resolve_name_timing, ResolveNameTiming);
static void manager_parse_udev_config(UdevConfig *config) {
assert(config);
const ConfigTableItem config_table[] = {
{ NULL, "udev_log", config_parse_log_level, 0, &config->log_level },
{ NULL, "children_max", config_parse_unsigned, 0, &config->children_max },
{ NULL, "exec_delay", config_parse_sec, 0, &config->exec_delay_usec },
{ NULL, "event_timeout", config_parse_sec, 0, &config->timeout_usec },
{ NULL, "resolve_names", config_parse_resolve_name_timing, 0, &config->resolve_name_timing },
{ NULL, "timeout_signal", config_parse_signal, 0, &config->timeout_signal },
{}
};
(void) udev_parse_config_full(config_table);
}
/*
* read the kernel command line, in case we need to get into debug mode
* udev.log_level=<level> syslog priority
* udev.children_max=<number of workers> events are fully serialized if set to 1
* udev.exec_delay=<number of seconds> delay execution of every executed program
* udev.event_timeout=<number of seconds> seconds to wait before terminating an event
* udev.blockdev_read_only<=bool> mark all block devices read-only when they appear
*/
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
UdevConfig *config = ASSERT_PTR(data);
int r;
assert(key);
if (proc_cmdline_key_streq(key, "udev.log_level") ||
proc_cmdline_key_streq(key, "udev.log_priority")) { /* kept for backward compatibility */
if (proc_cmdline_value_missing(key, value))
return 0;
r = log_level_from_string(value);
if (r >= 0)
config->log_level = r;
} else if (proc_cmdline_key_streq(key, "udev.event_timeout")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = parse_sec(value, &config->timeout_usec);
} else if (proc_cmdline_key_streq(key, "udev.children_max")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = safe_atou(value, &config->children_max);
} else if (proc_cmdline_key_streq(key, "udev.exec_delay")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = parse_sec(value, &config->exec_delay_usec);
} else if (proc_cmdline_key_streq(key, "udev.timeout_signal")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = signal_from_string(value);
if (r > 0)
config->timeout_signal = r;
} else if (proc_cmdline_key_streq(key, "udev.blockdev_read_only")) {
if (!value)
config->blockdev_read_only = true;
else {
r = parse_boolean(value);
if (r < 0)
log_warning_errno(r, "Failed to parse udev.blockdev-read-only argument, ignoring: %s", value);
else
config->blockdev_read_only = r;
}
if (config->blockdev_read_only)
log_notice("All physical block devices will be marked read-only.");
return 0;
} else {
if (startswith(key, "udev."))
log_warning("Unknown udev kernel command line option \"%s\", ignoring.", key);
return 0;
}
if (r < 0)
log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);
return 0;
}
static int help(void) {
_cleanup_free_ char *link = NULL;
int r;
r = terminal_urlify_man("systemd-udevd.service", "8", &link);
if (r < 0)
return log_oom();
printf("%s [OPTIONS...]\n\n"
"Rule-based manager for device events and files.\n\n"
" -h --help Print this message\n"
" -V --version Print version of the program\n"
" -d --daemon Detach and run in the background\n"
" -D --debug Enable debug output\n"
" -c --children-max=INT Set maximum number of workers\n"
" -e --exec-delay=SECONDS Seconds to wait before executing RUN=\n"
" -t --event-timeout=SECONDS Seconds to wait before terminating an event\n"
" -N --resolve-names=early|late|never\n"
" When to resolve users and groups\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
link);
return 0;
}
static int parse_argv(int argc, char *argv[], UdevConfig *config) {
enum {
ARG_TIMEOUT_SIGNAL,
};
static const struct option options[] = {
{ "daemon", no_argument, NULL, 'd' },
{ "debug", no_argument, NULL, 'D' },
{ "children-max", required_argument, NULL, 'c' },
{ "exec-delay", required_argument, NULL, 'e' },
{ "event-timeout", required_argument, NULL, 't' },
{ "resolve-names", required_argument, NULL, 'N' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "timeout-signal", required_argument, NULL, ARG_TIMEOUT_SIGNAL },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
assert(config);
while ((c = getopt_long(argc, argv, "c:de:Dt:N:hV", options, NULL)) >= 0) {
switch (c) {
case 'd':
arg_daemonize = true;
break;
case 'c':
r = safe_atou(optarg, &config->children_max);
if (r < 0)
log_warning_errno(r, "Failed to parse --children-max= value '%s', ignoring: %m", optarg);
break;
case 'e':
r = parse_sec(optarg, &config->exec_delay_usec);
if (r < 0)
log_warning_errno(r, "Failed to parse --exec-delay= value '%s', ignoring: %m", optarg);
break;
case ARG_TIMEOUT_SIGNAL:
r = signal_from_string(optarg);
if (r <= 0)
log_warning_errno(r, "Failed to parse --timeout-signal= value '%s', ignoring: %m", optarg);
else
config->timeout_signal = r;
break;
case 't':
r = parse_sec(optarg, &config->timeout_usec);
if (r < 0)
log_warning_errno(r, "Failed to parse --event-timeout= value '%s', ignoring: %m", optarg);
break;
case 'D':
arg_debug = true;
config->log_level = LOG_DEBUG;
break;
case 'N': {
ResolveNameTiming t;
t = resolve_name_timing_from_string(optarg);
if (t < 0)
log_warning("Invalid --resolve-names= value '%s', ignoring.", optarg);
else
config->resolve_name_timing = t;
break;
}
case 'h':
return help();
case 'V':
printf("%s\n", GIT_VERSION);
return 0;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
}
return 1;
}
#define MERGE_NON_NEGATIVE(name, default_value) \
manager->config.name = \
manager->config_by_control.name >= 0 ? manager->config_by_control.name : \
manager->config_by_kernel.name >= 0 ? manager->config_by_kernel.name : \
manager->config_by_command.name >= 0 ? manager->config_by_command.name : \
manager->config_by_udev_conf.name >= 0 ? manager->config_by_udev_conf.name : \
default_value;
#define MERGE_NON_ZERO(name, default_value) \
manager->config.name = \
manager->config_by_control.name ?: \
manager->config_by_kernel.name ?: \
manager->config_by_command.name ?: \
manager->config_by_udev_conf.name ?: \
default_value;
#define MERGE_BOOL(name) \
manager->config.name = \
manager->config_by_control.name || \
manager->config_by_kernel.name || \
manager->config_by_command.name || \
manager->config_by_udev_conf.name;
static void manager_merge_config(Manager *manager) {
assert(manager);
/* udev.conf has the lowest priority, then followed by command line arguments, kernel command line
options, and values set by udev control. */
MERGE_NON_NEGATIVE(log_level, log_get_max_level());
MERGE_NON_NEGATIVE(resolve_name_timing, RESOLVE_NAME_EARLY);
MERGE_NON_ZERO(exec_delay_usec, 0);
MERGE_NON_ZERO(timeout_usec, DEFAULT_WORKER_TIMEOUT_USEC);
MERGE_NON_ZERO(timeout_signal, SIGKILL);
MERGE_BOOL(blockdev_read_only);
}
void udev_config_set_default_children_max(UdevConfig *config) {
uint64_t cpu_limit, mem_limit, cpu_count = 1;
int r;
assert(config);
if (config->children_max != 0)
return;
r = cpus_in_affinity_mask();
if (r < 0)
log_warning_errno(r, "Failed to determine number of local CPUs, ignoring: %m");
else
cpu_count = r;
cpu_limit = cpu_count * 2 + 16;
mem_limit = MAX(physical_memory() / (128*1024*1024), UINT64_C(10));
config->children_max = MIN3(cpu_limit, mem_limit, WORKER_NUM_MAX);
log_debug("Set children_max to %u", config->children_max);
}
static void manager_adjust_config(UdevConfig *config) {
assert(config);
if (config->timeout_usec < MIN_WORKER_TIMEOUT_USEC) {
log_debug("Timeout (%s) for processing event is too small, using the default: %s",
FORMAT_TIMESPAN(config->timeout_usec, 1),
FORMAT_TIMESPAN(DEFAULT_WORKER_TIMEOUT_USEC, 1));
config->timeout_usec = DEFAULT_WORKER_TIMEOUT_USEC;
}
if (config->exec_delay_usec >= config->timeout_usec) {
log_debug("Delay (%s) for executing RUN= commands is too large compared with the timeout (%s) for event execution, ignoring the delay.",
FORMAT_TIMESPAN(config->exec_delay_usec, 1),
FORMAT_TIMESPAN(config->timeout_usec, 1));
config->exec_delay_usec = 0;
}
udev_config_set_default_children_max(config);
}
int manager_load(Manager *manager, int argc, char *argv[]) {
int r;
assert(manager);
manager_parse_udev_config(&manager->config_by_udev_conf);
r = parse_argv(argc, argv, &manager->config_by_command);
if (r <= 0)
return r;
r = proc_cmdline_parse(parse_proc_cmdline_item, &manager->config_by_kernel, PROC_CMDLINE_STRIP_RD_PREFIX);
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
manager_merge_config(manager);
if (arg_debug)
log_set_target(LOG_TARGET_CONSOLE);
log_set_max_level(manager->config.log_level);
manager_adjust_config(&manager->config);
return 1;
}
UdevReloadFlags manager_reload_config(Manager *manager) {
assert(manager);
UdevConfig old = manager->config;
manager->config_by_udev_conf = UDEV_CONFIG_INIT;
manager_parse_udev_config(&manager->config_by_udev_conf);
manager_merge_config(manager);
log_set_max_level(manager->config.log_level);
manager_adjust_config(&manager->config);
if (manager->config.resolve_name_timing != old.resolve_name_timing)
return UDEV_RELOAD_RULES | UDEV_RELOAD_KILL_WORKERS;
if (manager->config.log_level != old.log_level ||
manager->config.exec_delay_usec != old.exec_delay_usec ||
manager->config.timeout_usec != old.timeout_usec ||
manager->config.timeout_signal != old.timeout_signal ||
manager->config.blockdev_read_only != old.blockdev_read_only)
return UDEV_RELOAD_KILL_WORKERS;
return 0;
}

31
src/udev/udev-config.h Normal file
View File

@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <stdbool.h>
#include "time-util.h"
#include "udev-def.h"
extern bool arg_daemonize;
typedef struct Manager Manager;
typedef struct UdevConfig {
int log_level;
ResolveNameTiming resolve_name_timing;
unsigned children_max;
usec_t exec_delay_usec;
usec_t timeout_usec;
int timeout_signal;
bool blockdev_read_only;
} UdevConfig;
#define UDEV_CONFIG_INIT \
(UdevConfig) { \
.log_level = -1, \
.resolve_name_timing = _RESOLVE_NAME_TIMING_INVALID, \
}
int manager_load(Manager *manager, int argc, char *argv[]);
UdevReloadFlags manager_reload_config(Manager *manager);
void udev_config_set_default_children_max(UdevConfig *c);

View File

@ -55,3 +55,26 @@ typedef enum UdevBuiltinCommand {
_UDEV_BUILTIN_MAX, _UDEV_BUILTIN_MAX,
_UDEV_BUILTIN_INVALID = -EINVAL, _UDEV_BUILTIN_INVALID = -EINVAL,
} UdevBuiltinCommand; } UdevBuiltinCommand;
typedef enum UdevReloadFlags {
#if HAVE_BLKID
UDEV_RELOAD_BUILTIN_BLKID = 1u << UDEV_BUILTIN_BLKID,
#endif
UDEV_RELOAD_BUILTIN_BTRFS = 1u << UDEV_BUILTIN_BTRFS,
UDEV_RELOAD_BUILTIN_HWDB = 1u << UDEV_BUILTIN_HWDB,
UDEV_RELOAD_BUILTIN_INPUT_ID = 1u << UDEV_BUILTIN_INPUT_ID,
UDEV_RELOAD_BUILTIN_KEYBOARD = 1u << UDEV_BUILTIN_KEYBOARD,
#if HAVE_KMOD
UDEV_RELOAD_BUILTIN_KMOD = 1u << UDEV_BUILTIN_KMOD,
#endif
UDEV_RELOAD_BUILTIN_DRIVER = 1u << UDEV_BUILTIN_NET_DRIVER,
UDEV_RELOAD_BUILTIN_NET_ID = 1u << UDEV_BUILTIN_NET_ID,
UDEV_RELOAD_BUILTIN_NET_LINK = 1u << UDEV_BUILTIN_NET_LINK,
UDEV_RELOAD_BUILTIN_PATH_ID = 1u << UDEV_BUILTIN_PATH_ID,
UDEV_RELOAD_BUILTIN_USB_ID = 1u << UDEV_BUILTIN_USB_ID,
#if HAVE_ACL
UDEV_RELOAD_BUILTIN_UACCESS = 1u << UDEV_BUILTIN_UACCESS,
#endif
UDEV_RELOAD_KILL_WORKERS = 1u << (_UDEV_BUILTIN_MAX + 0),
UDEV_RELOAD_RULES = 1u << (_UDEV_BUILTIN_MAX + 1),
} UdevReloadFlags;

View File

@ -19,7 +19,7 @@
#include "user-util.h" #include "user-util.h"
UdevEvent* udev_event_new(sd_device *dev, UdevWorker *worker, EventMode mode) { UdevEvent* udev_event_new(sd_device *dev, UdevWorker *worker, EventMode mode) {
int log_level = worker ? worker->log_level : log_get_max_level(); int log_level = worker ? worker->config.log_level : log_get_max_level();
UdevEvent *event; UdevEvent *event;
assert(dev); assert(dev);

View File

@ -3,7 +3,6 @@
#include "blockdev-util.h" #include "blockdev-util.h"
#include "cgroup-util.h" #include "cgroup-util.h"
#include "common-signal.h" #include "common-signal.h"
#include "cpu-set-util.h"
#include "daemon-util.h" #include "daemon-util.h"
#include "device-monitor-private.h" #include "device-monitor-private.h"
#include "device-private.h" #include "device-private.h"
@ -15,7 +14,6 @@
#include "hashmap.h" #include "hashmap.h"
#include "inotify-util.h" #include "inotify-util.h"
#include "iovec-util.h" #include "iovec-util.h"
#include "limits-util.h"
#include "list.h" #include "list.h"
#include "mkdir.h" #include "mkdir.h"
#include "process-util.h" #include "process-util.h"
@ -25,6 +23,7 @@
#include "string-util.h" #include "string-util.h"
#include "syslog-util.h" #include "syslog-util.h"
#include "udev-builtin.h" #include "udev-builtin.h"
#include "udev-config.h"
#include "udev-ctrl.h" #include "udev-ctrl.h"
#include "udev-event.h" #include "udev-event.h"
#include "udev-manager.h" #include "udev-manager.h"
@ -36,8 +35,6 @@
#include "udev-watch.h" #include "udev-watch.h"
#include "udev-worker.h" #include "udev-worker.h"
#define WORKER_NUM_MAX UINT64_C(2048)
#define EVENT_RETRY_INTERVAL_USEC (200 * USEC_PER_MSEC) #define EVENT_RETRY_INTERVAL_USEC (200 * USEC_PER_MSEC)
#define EVENT_RETRY_TIMEOUT_USEC (3 * USEC_PER_MINUTE) #define EVENT_RETRY_TIMEOUT_USEC (3 * USEC_PER_MINUTE)
@ -243,7 +240,7 @@ static void notify_ready(Manager *manager) {
r = sd_notifyf(/* unset= */ false, r = sd_notifyf(/* unset= */ false,
"READY=1\n" "READY=1\n"
"STATUS=Processing with %u children at max", manager->children_max); "STATUS=Processing with %u children at max", manager->config.children_max);
if (r < 0) if (r < 0)
log_warning_errno(r, "Failed to send readiness notification, ignoring: %m"); log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
} }
@ -265,23 +262,26 @@ static void manager_reload(Manager *manager, bool force) {
/* Reload SELinux label database, to make the child inherit the up-to-date database. */ /* Reload SELinux label database, to make the child inherit the up-to-date database. */
mac_selinux_maybe_reload(); mac_selinux_maybe_reload();
/* Nothing changed. It is not necessary to reload. */ UdevReloadFlags flags = udev_builtin_should_reload();
if (!udev_rules_should_reload(manager->rules) && !udev_builtin_should_reload()) { if (udev_rules_should_reload(manager->rules))
flags |= UDEV_RELOAD_RULES | UDEV_RELOAD_KILL_WORKERS;
if (!force) if (flags == 0 && !force)
/* Neither .rules files nor config files for builtins e.g. .link files changed. It is not
* necessary to reload configs. Note, udev.conf is not checked in the above, hence reloaded
* when explicitly requested or at least one .rules file or friend is updated. */
return; return;
/* If we eat this up, then tell our service manager to just continue */
(void) notify_reloading_full("Skipping configuration reloading, nothing changed.");
} else {
(void) notify_reloading(); (void) notify_reloading();
flags |= manager_reload_config(manager);
if (FLAGS_SET(flags, UDEV_RELOAD_KILL_WORKERS))
manager_kill_workers(manager, false); manager_kill_workers(manager, false);
udev_builtin_exit(); udev_builtin_reload(flags);
udev_builtin_init();
r = udev_rules_load(&rules, manager->resolve_name_timing); if (FLAGS_SET(flags, UDEV_RELOAD_RULES)) {
r = udev_rules_load(&rules, manager->config.resolve_name_timing);
if (r < 0) if (r < 0)
log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m"); log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m");
else else
@ -306,7 +306,7 @@ static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
assert(event->manager); assert(event->manager);
assert(event->worker); assert(event->worker);
kill_and_sigcont(event->worker->pid, event->manager->timeout_signal); kill_and_sigcont(event->worker->pid, event->manager->config.timeout_signal);
event->worker->state = WORKER_KILLED; event->worker->state = WORKER_KILLED;
log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum); log_device_error(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" killed", event->worker->pid, event->seqnum);
@ -366,7 +366,7 @@ static void worker_attach_event(Worker *worker, Event *event) {
event->worker = worker; event->worker = worker;
(void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC, (void) sd_event_add_time_relative(e, &event->timeout_warning_event, CLOCK_MONOTONIC,
udev_warn_timeout(manager->timeout_usec), USEC_PER_SEC, udev_warn_timeout(manager->config.timeout_usec), USEC_PER_SEC,
on_event_timeout_warning, event); on_event_timeout_warning, event);
/* Manager.timeout_usec is also used as the timeout for running programs specified in /* Manager.timeout_usec is also used as the timeout for running programs specified in
@ -374,7 +374,7 @@ static void worker_attach_event(Worker *worker, Event *event) {
* kills a worker, to make it possible that the worker detects timed out of spawned programs, * kills a worker, to make it possible that the worker detects timed out of spawned programs,
* kills them, and finalizes the event. */ * kills them, and finalizes the event. */
(void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC, (void) sd_event_add_time_relative(e, &event->timeout_event, CLOCK_MONOTONIC,
usec_add(manager->timeout_usec, extra_timeout_usec()), USEC_PER_SEC, usec_add(manager->config.timeout_usec, extra_timeout_usec()), USEC_PER_SEC,
on_event_timeout, event); on_event_timeout, event);
} }
@ -408,11 +408,7 @@ static int worker_spawn(Manager *manager, Event *event) {
.rules = TAKE_PTR(manager->rules), .rules = TAKE_PTR(manager->rules),
.pipe_fd = TAKE_FD(manager->worker_watch[WRITE_END]), .pipe_fd = TAKE_FD(manager->worker_watch[WRITE_END]),
.inotify_fd = TAKE_FD(manager->inotify_fd), .inotify_fd = TAKE_FD(manager->inotify_fd),
.exec_delay_usec = manager->exec_delay_usec, .config = manager->config,
.timeout_usec = manager->timeout_usec,
.timeout_signal = manager->timeout_signal,
.log_level = manager->log_level,
.blockdev_read_only = manager->blockdev_read_only,
}; };
/* Worker process */ /* Worker process */
@ -461,10 +457,10 @@ static int event_run(Event *event) {
return 1; /* event is now processing. */ return 1; /* event is now processing. */
} }
if (hashmap_size(manager->workers) >= manager->children_max) { if (hashmap_size(manager->workers) >= manager->config.children_max) {
/* Avoid spamming the debug logs if the limit is already reached and /* Avoid spamming the debug logs if the limit is already reached and
* many events still need to be processed */ * many events still need to be processed */
if (log_children_max_reached && manager->children_max > 1) { if (log_children_max_reached && manager->config.children_max > 1) {
log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers)); log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers));
log_children_max_reached = false; log_children_max_reached = false;
} }
@ -845,28 +841,6 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
return 1; return 1;
} }
static void manager_set_default_children_max(Manager *manager) {
uint64_t cpu_limit, mem_limit, cpu_count = 1;
int r;
assert(manager);
if (manager->children_max != 0)
return;
r = cpus_in_affinity_mask();
if (r < 0)
log_warning_errno(r, "Failed to determine number of local CPUs, ignoring: %m");
else
cpu_count = r;
cpu_limit = cpu_count * 2 + 16;
mem_limit = MAX(physical_memory() / (128*1024*1024), UINT64_C(10));
manager->children_max = MIN3(cpu_limit, mem_limit, WORKER_NUM_MAX);
log_debug("Set children_max to %u", manager->children_max);
}
/* receive the udevd message from userspace */ /* receive the udevd message from userspace */
static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) { static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) {
Manager *manager = ASSERT_PTR(userdata); Manager *manager = ASSERT_PTR(userdata);
@ -888,7 +862,7 @@ static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrl
break; break;
log_set_max_level(value->intval); log_set_max_level(value->intval);
manager->log_level = value->intval; manager->config.log_level = manager->config_by_control.log_level = value->intval;
manager_kill_workers(manager, false); manager_kill_workers(manager, false);
break; break;
case UDEV_CTRL_STOP_EXEC_QUEUE: case UDEV_CTRL_STOP_EXEC_QUEUE:
@ -959,10 +933,11 @@ static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrl
} }
log_debug("Received udev control message (SET_MAX_CHILDREN), setting children_max=%i", value->intval); log_debug("Received udev control message (SET_MAX_CHILDREN), setting children_max=%i", value->intval);
manager->children_max = value->intval; manager->config_by_control.children_max = value->intval;
/* When 0 is specified, determine the maximum based on the system resources. */ /* When 0 is specified, determine the maximum based on the system resources. */
manager_set_default_children_max(manager); udev_config_set_default_children_max(&manager->config_by_control);
manager->config.children_max = manager->config_by_control.children_max;
notify_ready(manager); notify_ready(manager);
break; break;
@ -1199,35 +1174,16 @@ Manager* manager_new(void) {
*manager = (Manager) { *manager = (Manager) {
.inotify_fd = -EBADF, .inotify_fd = -EBADF,
.worker_watch = EBADF_PAIR, .worker_watch = EBADF_PAIR,
.log_level = LOG_INFO, .config_by_udev_conf = UDEV_CONFIG_INIT,
.resolve_name_timing = RESOLVE_NAME_EARLY, .config_by_command = UDEV_CONFIG_INIT,
.timeout_usec = DEFAULT_WORKER_TIMEOUT_USEC, .config_by_kernel = UDEV_CONFIG_INIT,
.timeout_signal = SIGKILL, .config_by_control = UDEV_CONFIG_INIT,
.config = UDEV_CONFIG_INIT,
}; };
return manager; return manager;
} }
void manager_adjust_arguments(Manager *manager) {
assert(manager);
if (manager->timeout_usec < MIN_WORKER_TIMEOUT_USEC) {
log_debug("Timeout (%s) for processing event is too small, using the default: %s",
FORMAT_TIMESPAN(manager->timeout_usec, 1),
FORMAT_TIMESPAN(DEFAULT_WORKER_TIMEOUT_USEC, 1));
manager->timeout_usec = DEFAULT_WORKER_TIMEOUT_USEC;
}
if (manager->exec_delay_usec >= manager->timeout_usec) {
log_debug("Delay (%s) for executing RUN= commands is too large compared with the timeout (%s) for event execution, ignoring the delay.",
FORMAT_TIMESPAN(manager->exec_delay_usec, 1),
FORMAT_TIMESPAN(manager->timeout_usec, 1));
manager->exec_delay_usec = 0;
}
}
static int listen_fds(int *ret_ctrl, int *ret_netlink) { static int listen_fds(int *ret_ctrl, int *ret_netlink) {
_cleanup_strv_free_ char **names = NULL; _cleanup_strv_free_ char **names = NULL;
_cleanup_close_ int ctrl_fd = -EBADF, netlink_fd = -EBADF; _cleanup_close_ int ctrl_fd = -EBADF, netlink_fd = -EBADF;
@ -1303,8 +1259,6 @@ int manager_init(Manager *manager) {
(void) sd_device_monitor_set_description(manager->monitor, "manager"); (void) sd_device_monitor_set_description(manager->monitor, "manager");
manager->log_level = log_get_max_level();
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup); r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
if (r < 0) if (r < 0)
log_debug_errno(r, "Failed to get cgroup, ignoring: %m"); log_debug_errno(r, "Failed to get cgroup, ignoring: %m");
@ -1319,8 +1273,6 @@ int manager_init(Manager *manager) {
int manager_main(Manager *manager) { int manager_main(Manager *manager) {
int fd_worker, r; int fd_worker, r;
manager_set_default_children_max(manager);
/* unnamed socket from workers to the main daemon */ /* unnamed socket from workers to the main daemon */
r = socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch); r = socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
if (r < 0) if (r < 0)
@ -1412,7 +1364,7 @@ int manager_main(Manager *manager) {
udev_builtin_init(); udev_builtin_init();
r = udev_rules_load(&manager->rules, manager->resolve_name_timing); r = udev_rules_load(&manager->rules, manager->config.resolve_name_timing);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to read udev rules: %m"); return log_error_errno(r, "Failed to read udev rules: %m");

View File

@ -9,6 +9,7 @@
#include "hashmap.h" #include "hashmap.h"
#include "macro.h" #include "macro.h"
#include "time-util.h" #include "time-util.h"
#include "udev-config.h"
#include "udev-ctrl.h" #include "udev-ctrl.h"
#include "udev-def.h" #include "udev-def.h"
@ -21,7 +22,6 @@ typedef struct Manager {
Hashmap *workers; Hashmap *workers;
LIST_HEAD(Event, events); LIST_HEAD(Event, events);
char *cgroup; char *cgroup;
int log_level;
UdevRules *rules; UdevRules *rules;
Hashmap *properties; Hashmap *properties;
@ -38,12 +38,11 @@ typedef struct Manager {
usec_t last_usec; usec_t last_usec;
ResolveNameTiming resolve_name_timing; UdevConfig config_by_udev_conf;
unsigned children_max; UdevConfig config_by_command;
usec_t exec_delay_usec; UdevConfig config_by_kernel;
usec_t timeout_usec; UdevConfig config_by_control;
int timeout_signal; UdevConfig config;
bool blockdev_read_only;
bool stop_exec_queue; bool stop_exec_queue;
bool exit; bool exit;
@ -53,7 +52,6 @@ Manager* manager_new(void);
Manager* manager_free(Manager *manager); Manager* manager_free(Manager *manager);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
void manager_adjust_arguments(Manager *manager);
int manager_init(Manager *manager); int manager_init(Manager *manager);
int manager_main(Manager *manager); int manager_main(Manager *manager);

View File

@ -240,8 +240,8 @@ int udev_event_spawn(
return 0; return 0;
} }
int timeout_signal = event->worker ? event->worker->timeout_signal : SIGKILL; int timeout_signal = event->worker ? event->worker->config.timeout_signal : SIGKILL;
usec_t timeout_usec = event->worker ? event->worker->timeout_usec : DEFAULT_WORKER_TIMEOUT_USEC; usec_t timeout_usec = event->worker ? event->worker->config.timeout_usec : DEFAULT_WORKER_TIMEOUT_USEC;
usec_t now_usec = now(CLOCK_MONOTONIC); usec_t now_usec = now(CLOCK_MONOTONIC);
usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec); usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec);
usec_t cmd_timeout_usec = usec_sub_unsigned(timeout_usec, age_usec); usec_t cmd_timeout_usec = usec_sub_unsigned(timeout_usec, age_usec);
@ -349,20 +349,20 @@ void udev_event_execute_run(UdevEvent *event) {
if (r < 0) if (r < 0)
log_device_debug_errno(event->dev, r, "Failed to run built-in command \"%s\", ignoring: %m", command); log_device_debug_errno(event->dev, r, "Failed to run built-in command \"%s\", ignoring: %m", command);
} else { } else {
if (event->worker && event->worker->exec_delay_usec > 0) { if (event->worker && event->worker->config.exec_delay_usec > 0) {
usec_t now_usec = now(CLOCK_MONOTONIC); usec_t now_usec = now(CLOCK_MONOTONIC);
usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec); usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec);
if (event->worker->exec_delay_usec >= usec_sub_unsigned(event->worker->timeout_usec, age_usec)) { if (event->worker->config.exec_delay_usec >= usec_sub_unsigned(event->worker->config.timeout_usec, age_usec)) {
log_device_warning(event->dev, log_device_warning(event->dev,
"Cannot delay execution of \"%s\" for %s, skipping.", "Cannot delay execution of \"%s\" for %s, skipping.",
command, FORMAT_TIMESPAN(event->worker->exec_delay_usec, USEC_PER_SEC)); command, FORMAT_TIMESPAN(event->worker->config.exec_delay_usec, USEC_PER_SEC));
continue; continue;
} }
log_device_debug(event->dev, "Delaying execution of \"%s\" for %s.", log_device_debug(event->dev, "Delaying execution of \"%s\" for %s.",
command, FORMAT_TIMESPAN(event->worker->exec_delay_usec, USEC_PER_SEC)); command, FORMAT_TIMESPAN(event->worker->config.exec_delay_usec, USEC_PER_SEC));
(void) usleep_safe(event->worker->exec_delay_usec); (void) usleep_safe(event->worker->config.exec_delay_usec);
} }
log_device_debug(event->dev, "Running command \"%s\"", command); log_device_debug(event->dev, "Running command \"%s\"", command);

View File

@ -194,7 +194,7 @@ static int worker_process_device(UdevWorker *worker, sd_device *dev) {
if (r < 0) if (r < 0)
return r; return r;
if (worker->blockdev_read_only) if (worker->config.blockdev_read_only)
(void) worker_mark_block_device_read_only(dev); (void) worker_mark_block_device_read_only(dev);
/* Disable watch during event processing. */ /* Disable watch during event processing. */
@ -321,7 +321,7 @@ static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device *
log_device_warning_errno(dev, r, "Failed to send signal to main daemon, ignoring: %m"); log_device_warning_errno(dev, r, "Failed to send signal to main daemon, ignoring: %m");
/* Reset the log level, as it might be changed by "OPTIONS=log_level=". */ /* Reset the log level, as it might be changed by "OPTIONS=log_level=". */
log_set_max_level(worker->log_level); log_set_max_level(worker->config.log_level);
return 1; return 1;
} }

View File

@ -10,6 +10,7 @@
#include "errno-list.h" #include "errno-list.h"
#include "hashmap.h" #include "hashmap.h"
#include "time-util.h" #include "time-util.h"
#include "udev-config.h"
#define DEFAULT_WORKER_TIMEOUT_USEC (3 * USEC_PER_MINUTE) #define DEFAULT_WORKER_TIMEOUT_USEC (3 * USEC_PER_MINUTE)
#define MIN_WORKER_TIMEOUT_USEC (1 * USEC_PER_MSEC) #define MIN_WORKER_TIMEOUT_USEC (1 * USEC_PER_MSEC)
@ -27,11 +28,7 @@ typedef struct UdevWorker {
int pipe_fd; int pipe_fd;
int inotify_fd; /* Do not close! */ int inotify_fd; /* Do not close! */
usec_t exec_delay_usec; UdevConfig config;
usec_t timeout_usec;
int timeout_signal;
int log_level;
bool blockdev_read_only;
} UdevWorker; } UdevWorker;
/* passed from worker to main process */ /* passed from worker to main process */

View File

@ -5,250 +5,17 @@
* Copyright © 2009 Scott James Remnant <scott@netsplit.com> * Copyright © 2009 Scott James Remnant <scott@netsplit.com>
*/ */
#include <getopt.h>
#include <unistd.h>
#include "conf-parser.h"
#include "env-file.h"
#include "errno-util.h" #include "errno-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "mkdir.h" #include "mkdir.h"
#include "parse-util.h"
#include "pretty-print.h"
#include "proc-cmdline.h"
#include "process-util.h" #include "process-util.h"
#include "rlimit-util.h" #include "rlimit-util.h"
#include "selinux-util.h" #include "selinux-util.h"
#include "signal-util.h" #include "udev-config.h"
#include "syslog-util.h"
#include "udev-manager.h" #include "udev-manager.h"
#include "udev-rules.h"
#include "udev-util.h"
#include "udevd.h" #include "udevd.h"
#include "version.h" #include "version.h"
static bool arg_debug = false;
static int arg_daemonize = false;
static DEFINE_CONFIG_PARSE_ENUM(config_parse_resolve_name_timing, resolve_name_timing, ResolveNameTiming);
static int manager_parse_udev_config(Manager *manager) {
int r, log_val = -1;
assert(manager);
const ConfigTableItem config_table[] = {
{ NULL, "udev_log", config_parse_log_level, 0, &log_val },
{ NULL, "children_max", config_parse_unsigned, 0, &manager->children_max },
{ NULL, "exec_delay", config_parse_sec, 0, &manager->exec_delay_usec },
{ NULL, "event_timeout", config_parse_sec, 0, &manager->timeout_usec },
{ NULL, "resolve_names", config_parse_resolve_name_timing, 0, &manager->resolve_name_timing },
{ NULL, "timeout_signal", config_parse_signal, 0, &manager->timeout_signal },
{}
};
r = udev_parse_config_full(config_table);
if (r < 0)
return r;
if (log_val >= 0)
log_set_max_level(log_val);
return 0;
}
/*
* read the kernel command line, in case we need to get into debug mode
* udev.log_level=<level> syslog priority
* udev.children_max=<number of workers> events are fully serialized if set to 1
* udev.exec_delay=<number of seconds> delay execution of every executed program
* udev.event_timeout=<number of seconds> seconds to wait before terminating an event
* udev.blockdev_read_only<=bool> mark all block devices read-only when they appear
*/
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
Manager *manager = ASSERT_PTR(data);
int r;
assert(key);
if (proc_cmdline_key_streq(key, "udev.log_level") ||
proc_cmdline_key_streq(key, "udev.log_priority")) { /* kept for backward compatibility */
if (proc_cmdline_value_missing(key, value))
return 0;
r = log_level_from_string(value);
if (r >= 0)
log_set_max_level(r);
} else if (proc_cmdline_key_streq(key, "udev.event_timeout")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = parse_sec(value, &manager->timeout_usec);
} else if (proc_cmdline_key_streq(key, "udev.children_max")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = safe_atou(value, &manager->children_max);
} else if (proc_cmdline_key_streq(key, "udev.exec_delay")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = parse_sec(value, &manager->exec_delay_usec);
} else if (proc_cmdline_key_streq(key, "udev.timeout_signal")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = signal_from_string(value);
if (r > 0)
manager->timeout_signal = r;
} else if (proc_cmdline_key_streq(key, "udev.blockdev_read_only")) {
if (!value)
manager->blockdev_read_only = true;
else {
r = parse_boolean(value);
if (r < 0)
log_warning_errno(r, "Failed to parse udev.blockdev-read-only argument, ignoring: %s", value);
else
manager->blockdev_read_only = r;
}
if (manager->blockdev_read_only)
log_notice("All physical block devices will be marked read-only.");
return 0;
} else {
if (startswith(key, "udev."))
log_warning("Unknown udev kernel command line option \"%s\", ignoring.", key);
return 0;
}
if (r < 0)
log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);
return 0;
}
static int help(void) {
_cleanup_free_ char *link = NULL;
int r;
r = terminal_urlify_man("systemd-udevd.service", "8", &link);
if (r < 0)
return log_oom();
printf("%s [OPTIONS...]\n\n"
"Rule-based manager for device events and files.\n\n"
" -h --help Print this message\n"
" -V --version Print version of the program\n"
" -d --daemon Detach and run in the background\n"
" -D --debug Enable debug output\n"
" -c --children-max=INT Set maximum number of workers\n"
" -e --exec-delay=SECONDS Seconds to wait before executing RUN=\n"
" -t --event-timeout=SECONDS Seconds to wait before terminating an event\n"
" -N --resolve-names=early|late|never\n"
" When to resolve users and groups\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
link);
return 0;
}
static int parse_argv(int argc, char *argv[], Manager *manager) {
enum {
ARG_TIMEOUT_SIGNAL,
};
static const struct option options[] = {
{ "daemon", no_argument, NULL, 'd' },
{ "debug", no_argument, NULL, 'D' },
{ "children-max", required_argument, NULL, 'c' },
{ "exec-delay", required_argument, NULL, 'e' },
{ "event-timeout", required_argument, NULL, 't' },
{ "resolve-names", required_argument, NULL, 'N' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "timeout-signal", required_argument, NULL, ARG_TIMEOUT_SIGNAL },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
assert(manager);
while ((c = getopt_long(argc, argv, "c:de:Dt:N:hV", options, NULL)) >= 0) {
switch (c) {
case 'd':
arg_daemonize = true;
break;
case 'c':
r = safe_atou(optarg, &manager->children_max);
if (r < 0)
log_warning_errno(r, "Failed to parse --children-max= value '%s', ignoring: %m", optarg);
break;
case 'e':
r = parse_sec(optarg, &manager->exec_delay_usec);
if (r < 0)
log_warning_errno(r, "Failed to parse --exec-delay= value '%s', ignoring: %m", optarg);
break;
case ARG_TIMEOUT_SIGNAL:
r = signal_from_string(optarg);
if (r <= 0)
log_warning_errno(r, "Failed to parse --timeout-signal= value '%s', ignoring: %m", optarg);
else
manager->timeout_signal = r;
break;
case 't':
r = parse_sec(optarg, &manager->timeout_usec);
if (r < 0)
log_warning_errno(r, "Failed to parse --event-timeout= value '%s', ignoring: %m", optarg);
break;
case 'D':
arg_debug = true;
break;
case 'N': {
ResolveNameTiming t;
t = resolve_name_timing_from_string(optarg);
if (t < 0)
log_warning("Invalid --resolve-names= value '%s', ignoring.", optarg);
else
manager->resolve_name_timing = t;
break;
}
case 'h':
return help();
case 'V':
printf("%s\n", GIT_VERSION);
return 0;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
}
return 1;
}
int run_udevd(int argc, char *argv[]) { int run_udevd(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *manager = NULL; _cleanup_(manager_freep) Manager *manager = NULL;
int r; int r;
@ -259,23 +26,10 @@ int run_udevd(int argc, char *argv[]) {
if (!manager) if (!manager)
return log_oom(); return log_oom();
manager_parse_udev_config(manager); r = manager_load(manager, argc, argv);
r = parse_argv(argc, argv, manager);
if (r <= 0) if (r <= 0)
return r; return r;
r = proc_cmdline_parse(parse_proc_cmdline_item, manager, PROC_CMDLINE_STRIP_RD_PREFIX);
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
if (arg_debug) {
log_set_target(LOG_TARGET_CONSOLE);
log_set_max_level(LOG_DEBUG);
}
manager_adjust_arguments(manager);
r = must_be_root(); r = must_be_root();
if (r < 0) if (r < 0)
return r; return r;

View File

@ -264,7 +264,7 @@ class UkifyConfig:
sbat: Optional[list[str]] sbat: Optional[list[str]]
sections: list['Section'] sections: list['Section']
sections_by_name: dict[str, 'Section'] sections_by_name: dict[str, 'Section']
sign_kernel: bool sign_kernel: Optional[bool]
signing_engine: Optional[str] signing_engine: Optional[str]
signing_provider: Optional[str] signing_provider: Optional[str]
certificate_provider: Optional[str] certificate_provider: Optional[str]
@ -1108,7 +1108,7 @@ def make_uki(opts: UkifyConfig) -> None:
assert opts.signtool is not None assert opts.signtool is not None
signtool = SignTool.from_string(opts.signtool) signtool = SignTool.from_string(opts.signtool)
if not sign_kernel: if sign_kernel is None:
# figure out if we should sign the kernel # figure out if we should sign the kernel
sign_kernel = signtool.verify(opts) sign_kernel = signtool.verify(opts)

View File

@ -53,6 +53,12 @@ static int get_startup_monotonic_time(Context *c, usec_t *ret) {
assert(c); assert(c);
assert(ret); assert(ret);
if (!c->bus) {
r = bus_connect_system_systemd(&c->bus);
if (r < 0)
return log_warning_errno(r, "Failed to get D-Bus connection, ignoring: %m");
}
r = bus_get_property_trivial( r = bus_get_property_trivial(
c->bus, c->bus,
bus_systemd_mgr, bus_systemd_mgr,
@ -94,10 +100,13 @@ static int get_current_runlevel(Context *c) {
UINT64_C(100) * USEC_PER_MSEC + UINT64_C(100) * USEC_PER_MSEC +
random_u64_range(UINT64_C(1900) * USEC_PER_MSEC * n_attempts / MAX_ATTEMPTS); random_u64_range(UINT64_C(1900) * USEC_PER_MSEC * n_attempts / MAX_ATTEMPTS);
(void) usleep_safe(usec); (void) usleep_safe(usec);
}
if (!c->bus) {
r = bus_connect_system_systemd(&c->bus); r = bus_connect_system_systemd(&c->bus);
if (r == -ECONNREFUSED && n_attempts < 64) { if (r == -ECONNREFUSED && n_attempts < 64) {
log_debug_errno(r, "Failed to reconnect to system bus, retrying after a slight delay: %m"); log_debug_errno(r, "Failed to %s to system bus, retrying after a slight delay: %m",
n_attempts <= 1 ? "connect" : "reconnect");
continue; continue;
} }
if (r < 0) if (r < 0)
@ -251,7 +260,6 @@ static int run(int argc, char *argv[]) {
.audit_fd = -EBADF, .audit_fd = -EBADF,
#endif #endif
}; };
int r;
log_setup(); log_setup();
@ -264,9 +272,6 @@ static int run(int argc, char *argv[]) {
log_full_errno(IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT) ? LOG_DEBUG : LOG_WARNING, log_full_errno(IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT) ? LOG_DEBUG : LOG_WARNING,
errno, "Failed to connect to audit log, ignoring: %m"); errno, "Failed to connect to audit log, ignoring: %m");
#endif #endif
r = bus_connect_system_systemd(&c.bus);
if (r < 0)
return log_error_errno(r, "Failed to get D-Bus connection: %m");
return dispatch_verb(argc, argv, verbs, &c); return dispatch_verb(argc, argv, verbs, &c);
} }

View File

@ -3,5 +3,11 @@
integration_tests += [ integration_tests += [
integration_test_template + { integration_test_template + {
'name' : fs.name(meson.current_source_dir()), 'name' : fs.name(meson.current_source_dir()),
'configuration' : integration_test_template['configuration'] + {
# Do not request user session, as it may trigger to start
# hostnamed in an unexpected timing, and the test may fail.
'wants' : 'multi-user.target',
'after' : 'multi-user.target',
},
}, },
] ]

View File

@ -42,6 +42,8 @@ create_dummy_container /var/lib/machines/long-running
cat >/var/lib/machines/long-running/sbin/init <<\EOF cat >/var/lib/machines/long-running/sbin/init <<\EOF
#!/usr/bin/bash #!/usr/bin/bash
set -x
PID=0 PID=0
trap 'touch /terminate; kill 0' RTMIN+3 trap 'touch /terminate; kill 0' RTMIN+3
@ -310,6 +312,10 @@ varlinkctl call /run/systemd/machine/io.systemd.Machine io.systemd.Machine.Unreg
# test io.systemd.Machine.List with addresses, OSRelease, and UIDShift fields # test io.systemd.Machine.List with addresses, OSRelease, and UIDShift fields
create_dummy_container "/var/lib/machines/container-without-os-release" create_dummy_container "/var/lib/machines/container-without-os-release"
cat >>/var/lib/machines/container-without-os-release/sbin/init <<\EOF cat >>/var/lib/machines/container-without-os-release/sbin/init <<\EOF
#!/usr/bin/bash
set -x
ip link add hoge type dummy ip link add hoge type dummy
ip link set hoge up ip link set hoge up
ip address add 192.0.2.1/24 dev hoge ip address add 192.0.2.1/24 dev hoge

View File

@ -27,7 +27,7 @@ event_timeout=10
timeout_signal=SIGABRT timeout_signal=SIGABRT
EOF EOF
systemctl restart systemd-udevd.service systemctl reload systemd-udevd.service
} }
# shellcheck disable=SC2317 # shellcheck disable=SC2317
@ -40,7 +40,7 @@ teardown() {
rm -rf "$TMPDIR" rm -rf "$TMPDIR"
rm -f "$TEST_RULE" "$TEST_CONF" rm -f "$TEST_RULE" "$TEST_CONF"
systemctl restart systemd-udevd.service systemctl reload systemd-udevd.service
} }
run_test_timeout() { run_test_timeout() {

View File

@ -18,7 +18,7 @@ at_exit() {
# Forcibly kills sleep command invoked by the udev rule before restarting, # Forcibly kills sleep command invoked by the udev rule before restarting,
# otherwise systemctl restart below will takes longer. # otherwise systemctl restart below will takes longer.
killall -KILL sleep killall -KILL sleep
systemctl restart systemd-udevd.service udevadm control --reload
ip link del "$IFNAME" ip link del "$IFNAME"
} }
@ -31,18 +31,50 @@ cat >/run/udev/udev.conf.d/timeout.conf <<EOF
event_timeout=1h event_timeout=1h
EOF EOF
# First, test 'add' event.
mkdir -p /run/udev/rules.d/ mkdir -p /run/udev/rules.d/
cat >/run/udev/rules.d/99-testsuite.rules <<EOF cat >/run/udev/rules.d/99-testsuite.rules <<EOF
SUBSYSTEM=="net", ACTION=="change", KERNEL=="${IFNAME}", OPTIONS="log_level=debug", RUN+="/usr/bin/sleep 1000" SUBSYSTEM=="net", ACTION=="add", KERNEL=="${IFNAME}", OPTIONS="log_level=debug", RUN+="/usr/bin/sleep 1000"
EOF EOF
systemctl restart systemd-udevd.service udevadm control --reload
ip link add "$IFNAME" type dummy ip link add "$IFNAME" type dummy
IFINDEX=$(ip -json link show "$IFNAME" | jq '.[].ifindex') IFINDEX=$(ip -json link show "$IFNAME" | jq '.[].ifindex')
udevadm wait --timeout 10 "/sys/class/net/${IFNAME}" timeout 30 bash -c "until [[ -e /run/udev/data/n${IFINDEX} ]] && grep -q -F 'ID_PROCESSING=1' /run/udev/data/n${IFINDEX}; do sleep .5; done"
# Check if the database file is created.
[[ -e "/run/udev/data/n${IFINDEX}" ]] (! systemctl is-active "sys-devices-virtual-net-${IFNAME}.device")
(! systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device")
for _ in {1..3}; do
systemctl daemon-reexec
(! systemctl is-active "sys-devices-virtual-net-${IFNAME}.device")
(! systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device")
done
for _ in {1..3}; do
systemctl daemon-reload
(! systemctl is-active "sys-devices-virtual-net-${IFNAME}.device")
(! systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device")
done
# Check if the reexec and reload have finished during processing the event.
grep -q -F 'ID_PROCESSING=1' "/run/udev/data/n${IFINDEX}"
# Forcibly kill sleep command ivoked by the udev rule to finish processing the add event.
killall sleep
udevadm settle --timeout=20
# Check if ID_PROCESSING flag is unset, and the device units are active.
(! grep -q -F 'ID_PROCESSING=1' "/run/udev/data/n${IFINDEX}")
systemctl is-active "sys-devices-virtual-net-${IFNAME}.device"
systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device"
# Next, test 'change' event.
cat >/run/udev/rules.d/99-testsuite.rules <<EOF
SUBSYSTEM=="net", ACTION=="change", KERNEL=="${IFNAME}", OPTIONS="log_level=debug", RUN+="/usr/bin/sleep 1000"
EOF
udevadm control --reload
systemd-run \ systemd-run \
-p After="sys-subsystem-net-devices-${IFNAME}.device" \ -p After="sys-subsystem-net-devices-${IFNAME}.device" \
@ -50,22 +82,29 @@ systemd-run \
-u testsleep.service \ -u testsleep.service \
sleep 1h sleep 1h
timeout 10 bash -c 'until systemctl is-active testsleep.service; do sleep .5; done'
udevadm trigger "/sys/class/net/${IFNAME}" udevadm trigger "/sys/class/net/${IFNAME}"
timeout 30 bash -c "until grep -F 'ID_PROCESSING=1' /run/udev/data/n${IFINDEX}; do sleep .5; done" timeout 30 bash -c "until grep -q -F 'ID_PROCESSING=1' /run/udev/data/n${IFINDEX}; do sleep .5; done"
# Check if the service and device units are still active even ID_PROCESSING flag is set.
systemctl is-active testsleep.service
systemctl is-active "sys-devices-virtual-net-${IFNAME}.device"
systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device"
for _ in {1..3}; do for _ in {1..3}; do
systemctl daemon-reexec systemctl daemon-reexec
systemctl is-active testsleep.service systemctl is-active testsleep.service
systemctl is-active "sys-devices-virtual-net-${IFNAME}.device"
systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device"
done done
for _ in {1..3}; do for _ in {1..3}; do
systemctl daemon-reload systemctl daemon-reload
systemctl is-active testsleep.service systemctl is-active testsleep.service
systemctl is-active "sys-devices-virtual-net-${IFNAME}.device"
systemctl is-active "sys-subsystem-net-devices-${IFNAME}.device"
done done
# Check if the reexec and reload have finished during processing the event. # Check if the reexec and reload have finished during processing the event.
grep -F 'ID_PROCESSING=1' "/run/udev/data/n${IFINDEX}" grep -q -F 'ID_PROCESSING=1' "/run/udev/data/n${IFINDEX}"
exit 0 exit 0

View File

@ -85,31 +85,25 @@ systemd-run \
--wait \ --wait \
-p RootImage="$MINIMAL_IMAGE.raw" \ -p RootImage="$MINIMAL_IMAGE.raw" \
-p NotifyAccess=all \ -p NotifyAccess=all \
--service-type=notify \
--pipe \
bash -xec \ bash -xec \
' '
printf MAINPID=$$$$\\nREADY=1 | ncat --unixsock --udp $NOTIFY_SOCKET --source /run/notify
[[ "$$NOTIFY_SOCKET" == "/run/host/notify" ]] [[ "$$NOTIFY_SOCKET" == "/run/host/notify" ]]
[[ "$$(env)" =~ "NOTIFY_SOCKET=/run/host/notify" ]]
test -S /run/host/notify test -S /run/host/notify
' '
if [[ "$(findmnt -n -o FSTYPE /)" == btrfs ]]; then if [[ "$(findmnt -n -o FSTYPE /)" == btrfs ]]; then
[[ -d /test-dissect-btrfs-snapshot ]] && btrfs subvolume delete /test-dissect-btrfs-snapshot [[ -d /test-dissect-btrfs-snapshot ]] && btrfs subvolume delete /test-dissect-btrfs-snapshot
btrfs subvolume snapshot / /test-dissect-btrfs-snapshot btrfs subvolume snapshot / /test-dissect-btrfs-snapshot
# Same test with systemd-notify and RootDirectory= # Same test with RootDirectory=, also try to send READY=1, as we can use systemd-notify.
systemd-run \ systemd-run \
--wait \ --wait \
-p RootDirectory=/test-dissect-btrfs-snapshot \ -p RootDirectory=/test-dissect-btrfs-snapshot \
-p NotifyAccess=all \ -p NotifyAccess=all \
--service-type=notify \ --service-type=notify \
--pipe \
bash -xec \ bash -xec \
' '
systemd-notify --pid=auto --ready systemd-notify --pid=auto --ready
[[ "$$NOTIFY_SOCKET" == "/run/host/notify" ]] [[ "$$NOTIFY_SOCKET" == "/run/host/notify" ]]
[[ "$(env)" =~ "NOTIFY_SOCKET=/run/host/notify" ]]
test -S /run/host/notify test -S /run/host/notify
' '

View File

@ -490,7 +490,7 @@ cmp /tmp/vlcredsdata /tmp/vlcredsdata2
rm /tmp/vlcredsdata /tmp/vlcredsdata2 rm /tmp/vlcredsdata /tmp/vlcredsdata2
clean_usertest() { clean_usertest() {
rm -f /tmp/usertest.data /tmp/usertest.data rm -f /tmp/usertest.data /tmp/usertest.data /tmp/brummbaer.data
} }
trap clean_usertest EXIT trap clean_usertest EXIT
@ -520,6 +520,12 @@ XDG_RUNTIME_DIR=/run/user/0 systemd-run --pipe --user --unit=waldi.service -p Lo
# Test mount unit with credential # Test mount unit with credential
test_mount_with_credential test_mount_with_credential
# Fully unpriv operation
dd if=/dev/urandom of=/tmp/brummbaer.data bs=4096 count=1
run0 -u testuser --pipe mkdir -p /home/testuser/.config/credstore.encrypted
run0 -u testuser --pipe systemd-creds encrypt --user --name=brummbaer - /home/testuser/.config/credstore.encrypted/brummbaer < /tmp/brummbaer.data
run0 -u testuser --pipe systemd-run --user --pipe -p ImportCredential=brummbaer systemd-creds cat brummbaer | cmp /tmp/brummbaer.data
systemd-analyze log-level info systemd-analyze log-level info
touch /testok touch /testok

View File

@ -990,6 +990,11 @@ systemd-analyze architectures uname
systemd-analyze smbios11 systemd-analyze smbios11
systemd-analyze smbios11 -q systemd-analyze smbios11 -q
if test -f /sys/class/dmi/id/board_vendor && ! systemd-detect-virt --container ; then
systemd-analyze chid
systemd-analyze chid --json=pretty
fi
systemd-analyze condition --instance=tmp --unit=systemd-growfs@.service systemd-analyze condition --instance=tmp --unit=systemd-growfs@.service
systemd-analyze verify --instance=tmp --man=no systemd-growfs@.service systemd-analyze verify --instance=tmp --man=no systemd-growfs@.service
systemd-analyze security --instance=tmp systemd-growfs@.service systemd-analyze security --instance=tmp systemd-growfs@.service

View File

@ -69,6 +69,51 @@ SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/default.target.wants/debug-shell.service" /lib/systemd/system/debug-shell.service link_endswith "$OUT_DIR/early/default.target.wants/debug-shell.service" /lib/systemd/system/debug-shell.service
grep -F "/dev/tty666" "$OUT_DIR/early/debug-shell.service.d/50-tty.conf" grep -F "/dev/tty666" "$OUT_DIR/early/debug-shell.service.d/50-tty.conf"
# systemd.break (default)
: "debug-shell: regular + systemd.break"
CMDLINE="$CMDLINE systemd.break"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-mount.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-switch-root.service"
# systemd.break=pre-switch-root
: "debug-shell: regular + systemd.break=pre-switch-root"
CMDLINE="$CMDLINE systemd.break=pre-switch-root"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-mount.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-switch-root.service"
# systemd.break=pre-mount
: "debug-shell: regular + systemd.break=pre-mount"
CMDLINE="$CMDLINE systemd.break=pre-mount"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-mount.service"
test ! -h "$OUT_DIR/early/default.target.wants/breakpoint-pre-switch-root.service"
# systemd.break=pre-basic
: "debug-shell: regular + systemd.break=pre-basic"
CMDLINE="$CMDLINE systemd.break=pre-basic"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/default.target.wants/breakpoint-pre-basic.service" /lib/systemd/system/breakpoint-pre-basic.service
# systemd.break=pre-udev
: "debug-shell: regular + systemd.break=pre-udev"
CMDLINE="$CMDLINE systemd.break=pre-udev"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service" /lib/systemd/system/breakpoint-pre-udev.service
# systemd.break=pre-udev,pre-basic,pre-mount,pre-switch-root
: "debug-shell: regular + systemd.break=pre-udev,pre-basic,pre-mount,pre-switch-root"
rm -f "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service"
rm -f "$OUT_DIR/early/default.target.wants/breakpoint-pre-basic.service"
CMDLINE="$CMDLINE systemd.break=pre-udev,pre-basic,pre-mount,pre-switch-root"
SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/default.target.wants/breakpoint-pre-udev.service" /lib/systemd/system/breakpoint-pre-udev.service
link_endswith "$OUT_DIR/early/default.target.wants/breakpoint-pre-basic.service" /lib/systemd/system/breakpoint-pre-basic.service
# Now override the default target via systemd.unit= # Now override the default target via systemd.unit=
: "debug-shell: regular + systemd.unit=" : "debug-shell: regular + systemd.unit="
CMDLINE="$CMDLINE systemd.unit=my-fancy.target" CMDLINE="$CMDLINE systemd.unit=my-fancy.target"
@ -103,6 +148,50 @@ CMDLINE="$CMDLINE rd.systemd.debug_shell"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR" SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/debug-shell.service" /lib/systemd/system/debug-shell.service link_endswith "$OUT_DIR/early/initrd.target.wants/debug-shell.service" /lib/systemd/system/debug-shell.service
# rd.systemd.break (default)
: "debug-shell: initrd + rd.systemd.break"
CMDLINE="$CMDLINE rd.systemd.break"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-switch-root.service" /lib/systemd/system/breakpoint-pre-switch-root.service
# rd.systemd.break=pre-udev
: "debug-shell: initrd + rd.systemd.break=pre-udev"
CMDLINE="$CMDLINE rd.systemd.break=pre-udev"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-udev.service" /lib/systemd/system/breakpoint-pre-udev.service
# rd.systemd.break=pre-basic
: "debug-shell: initrd + rd.systemd.break=pre-basic"
CMDLINE="$CMDLINE rd.systemd.break=pre-basic"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-basic.service" /lib/systemd/system/breakpoint-pre-basic.service
# rd.systemd.break=pre-mount
: "debug-shell: initrd + rd.systemd.break=pre-mount"
CMDLINE="$CMDLINE rd.systemd.break=pre-mount"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-mount.service" /lib/systemd/system/breakpoint-pre-mount.service
# rd.systemd.break=pre-switch-root
: "debug-shell: initrd + rd.systemd.break=pre-switch-root"
rm -f "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-switch-root.service"
CMDLINE="$CMDLINE rd.systemd.break=pre-switch-root"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-switch-root.service" /lib/systemd/system/breakpoint-pre-switch-root.service
# rd.systemd.break=pre-udev,pre-basic,pre-mount,pre-switch-root
: "debug-shell: initrd + rd.systemd.break=pre-udev,pre-mount,pre-switch-root"
rm -f "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-udev.service"
rm -f "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-basic.service"
rm -f "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-mount.service"
rm -f "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-switch-root.service"
CMDLINE="$CMDLINE rd.systemd.break=pre-udev,pre-basic,pre-mount,pre-switch-root"
SYSTEMD_IN_INITRD=1 SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR"
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-udev.service" /lib/systemd/system/breakpoint-pre-udev.service
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-basic.service" /lib/systemd/system/breakpoint-pre-basic.service
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-mount.service" /lib/systemd/system/breakpoint-pre-mount.service
link_endswith "$OUT_DIR/early/initrd.target.wants/breakpoint-pre-switch-root.service" /lib/systemd/system/breakpoint-pre-switch-root.service
# Override the default target # Override the default target
: "debug-shell: initrd + rd.systemd.unit" : "debug-shell: initrd + rd.systemd.unit"
CMDLINE="$CMDLINE rd.systemd.unit=my-fancy-initrd.target" CMDLINE="$CMDLINE rd.systemd.unit=my-fancy-initrd.target"

View File

@ -0,0 +1,35 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Breakpoint Before Basic System
Documentation=man:systemd-debug-generator(8)
DefaultDependencies=no
Conflicts=shutdown.target emergency.target
After=sysinit.target sockets.target paths.target slices.target tmp.mount systemd-vconsole-setup.service
Before=basic.target
[Service]
Environment=SHELL_PROMPT_PREFIX="pre-basic "
Type=oneshot
ExecStartPre=-plymouth --wait quit
# Execute shell with "-" prefix to not consider the unit failed if it exits with
# a non-zero value
ExecStart=-{{SUSHELL}}
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
# bash ignores SIGTERM
KillSignal=SIGHUP
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
UnsetEnvironment=LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION

View File

@ -0,0 +1,36 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Breakpoint Before Mounting the Root Filesystem on /sysroot
Documentation=man:systemd-debug-generator(8)
AssertPathExists=/etc/initrd-release
DefaultDependencies=no
Conflicts=shutdown.target emergency.target
After=basic.target systemd-vconsole-setup.service
Before=initrd-root-fs.target sysroot.mount systemd-fsck-root.service
[Service]
Environment=SHELL_PROMPT_PREFIX="pre-mount "
Type=oneshot
ExecStartPre=-plymouth --wait quit
# Execute shell with "-" prefix to not consider the unit failed if it exits with
# a non-zero value
ExecStart=-{{SUSHELL}}
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
# bash ignores SIGTERM
KillSignal=SIGHUP
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
UnsetEnvironment=LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION

View File

@ -0,0 +1,37 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Breakpoint Before Switching Root
Documentation=man:systemd-debug-generator(8)
AssertPathExists=/etc/initrd-release
DefaultDependencies=no
Conflicts=shutdown.target emergency.target
Wants=remote-fs.target
After=initrd.target initrd-parse-etc.service sysroot.mount remote-fs.target systemd-vconsole-setup.service
Before=initrd-cleanup.service
[Service]
Environment=SHELL_PROMPT_PREFIX="pre-switch-root "
Type=oneshot
ExecStartPre=-plymouth --wait quit
# Execute shell with "-" prefix to not consider the unit failed if it exits with
# a non-zero value
ExecStart=-{{SUSHELL}}
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
# bash ignores SIGTERM
KillSignal=SIGHUP
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
UnsetEnvironment=LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION

View File

@ -0,0 +1,36 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Breakpoint Before Starting to Process Kernel uevents
Documentation=man:systemd-debug-generator(8)
DefaultDependencies=no
Conflicts=shutdown.target emergency.target
Wants=systemd-journald.socket
After=systemd-journald.socket systemd-vconsole-setup.service
Before=systemd-udevd.service systemd-udev-trigger.service
[Service]
Environment=SHELL_PROMPT_PREFIX="pre-udev "
Type=oneshot
ExecStartPre=-plymouth --wait quit
# Execute shell with "-" prefix to not consider the unit failed if it exits with
# a non-zero value
ExecStart=-{{SUSHELL}}
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
KillMode=process
IgnoreSIGPIPE=no
# bash ignores SIGTERM
KillSignal=SIGHUP
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
UnsetEnvironment=LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION

View File

@ -7,6 +7,10 @@ units = [
{ 'file' : 'blockdev@.target' }, { 'file' : 'blockdev@.target' },
{ 'file' : 'bluetooth.target' }, { 'file' : 'bluetooth.target' },
{ 'file' : 'boot-complete.target' }, { 'file' : 'boot-complete.target' },
{ 'file' : 'breakpoint-pre-basic.service.in' },
{ 'file' : 'breakpoint-pre-mount.service.in' },
{ 'file' : 'breakpoint-pre-switch-root.service.in' },
{ 'file' : 'breakpoint-pre-udev.service.in' },
{ 'file' : 'capsule@.service.in' }, { 'file' : 'capsule@.service.in' },
{ 'file' : 'capsule.slice' }, { 'file' : 'capsule.slice' },
{ 'file' : 'console-getty.service.in' }, { 'file' : 'console-getty.service.in' },