Commit Graph
147 Commits
Author SHA1 Message Date
Daan De Meyer 74d392ed1b tree-wide: standardize header names across src/fundamental, src/basic and src/shared
Drop the -fundamental suffix from src/fundamental/ headers in favor of names
that match their src/basic/ or src/shared/ counterparts (e.g.
macro-fundamental.h -> macro.h, assert-fundamental.h -> assert-util.h,
cleanup-fundamental.h -> cleanup-util.h). Rename src/basic/{btrfs,label}.{c,h}
to use the -util suffix to match the existing shared/btrfs-util and
shared/label-util siblings. Rename src/shared/mkdir-label.{c,h} to mkdir.{c,h}
and src/shared/tmpfile-util-label.{c,h} to tmpfile-util.{c,h} to match the
corresponding src/basic names.

This saves us from having to come up with separate names for files that do
the same thing across tiers, and it makes it easier to move stuff between
src/fundamental, src/basic and src/shared: consumers just #include "foo.h"
and pick up whichever tier their -I path resolves to first, so call sites
don't need to be updated when an API moves between layers.

Where a higher-tier wrapper exists (e.g. src/basic/macro.h wrapping
src/fundamental/macro.h), the wrapper uses an explicit "../fundamental/foo.h"
or "../basic/foo.h" relative include for the lower-tier header. We can't use
GCC's #include_next directive for this — when the wrapper is reachable both
via same-dir-as-source lookup and via -I (e.g. -Isrc/shared) for the
directory it lives in, #include_next advances by exactly one slot in libcpp's
internal directory chain and lands on the same physical directory it was
already in, never reaching the lower-tier sibling (see make_cpp_dir() in
gcc/libcpp/files.cc:1986).

To make sure the right headers are always picked up, the include directories
are reordered so that e.g. src/shared always takes priority over src/basic and
similar for the other directories.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 10:33:03 +09:00
Lennart Poettering ad19aced00 bootctl: show platform lang in bootctl status output 2026-05-20 16:38:19 +02:00
Zbigniew Jędrzejewski-Szmek 39a3647539 tree-wide: get rid of old dispatch_verb
Also rename dispatch_verb_with_args to dispatch_verb.
2026-05-16 18:37:10 +02:00
Zbigniew Jędrzejewski-Szmek 587c522487 various: fix duplicated logging from parse_path_argument
As pointed out in review, parse_path_argument can fail for non-oom reasons.
But the function already logs, so the correct thing to do is to just
propagate the error.
2026-05-14 14:15:55 +02:00
Zbigniew Jędrzejewski-Szmek 92fbc11f6a shared/options: introduce OPTION_COMMON_{ENTRY_TOKEN,MAKE_ENTRY_DIRECTORY} 2026-05-14 13:00:11 +02:00
Daan De Meyer 7b9d76cba7 boot,vconsole: Propagate UEFI HII keyboard layout to the OS
UEFI firmware can report the currently-active keyboard layout via
EFI_HII_DATABASE_PROTOCOL.GetKeyboardLayout(). The layout descriptor
includes an RFC 4646 / BCP 47 language tag (e.g. "en-US"). Query this
from sd-boot/sd-stub and write it to a new LoaderKeyboardLayout EFI
variable, advertised through a new EFI_LOADER_FEATURE_KEYBOARD_LAYOUT
feature bit.

On the OS side, systemd-vconsole-setup reads the variable as a
lowest-priority fallback for the console keymap. To map the BCP 47
tag to a vconsole keymap we extend /usr/share/systemd/kbd-model-map
with an optional sixth column listing the comma-separated BCP 47 tags
each row covers; a new find_vconsole_keymap_for_bcp47() helper walks
the file, preferring an exact tag match and otherwise falling back to
the row whose tag matches the input's primary subtag. Credentials,
/etc/vconsole.conf, and vconsole.keymap= on the kernel command line
continue to take precedence.

bootctl status surfaces the new variable, printing the language tag
or "n/a (not reported by firmware)" when sd-boot advertises the
feature but the firmware HII database didn't expose a layout (common
on QEMU without a USB keyboard, since EDK2's PS/2 driver does not
register an HII keyboard layout).
2026-05-11 21:10:11 +02:00
Zbigniew Jędrzejewski-Szmek 5afd344438 bootctl,mute-console,pcrextend,pcrlock,repart: allow connections from self
With SD_VARLINK_SERVER_ROOT_ONLY, we refuse all unprivileged operations.
This is silly, the user can and should be able to do anything that doesn't
require privileges.

E.g.:

$ SYSTEMD_LOG_LEVEL=debug varlinkctl introspect /usr/lib/systemd/systemd-pcrextend
Forking off Varlink child process '/usr/lib/systemd/systemd-pcrextend'.
Successfully forked off '(sd-vlexec)' as PID 568993.
varlink: Setting state idle-client
json-stream: Sending message: {"method":"org.varlink.service.GetInterfaceDescription","parameters":{"interface":"io.systemd.PCRExtend"}}
Skipping PR_SET_MM, as we don't have privileges.
varlink: Changing state idle-client → calling
varlink: Unprivileged client attempted connection, refusing.
Failed to run Varlink event loop: Operation not permitted
json-stream: Got POLLHUP from socket.
varlink: Changing state calling → pending-disconnect
varlink: Connection was closed.
Failed to issue org.varlink.service.GetInterfaceDescription() varlink call: Connection reset by peer

This and similar commands now work, e.g.

$ SYSTEMD_LOG_LEVEL=debug varlinkctl call --more ./build/bootctl io.systemd.BootControl.ListBootEntries {}
...
Failed to open directory "/efi": No such file or directory
File system "/boot" is not a FAT EFI System Partition (ESP) file system.
...
Method call failed: Permission denied
{
	"origin" : "linux",
	"errno" : 13,
	"errnoName" : "EACCES"
}
Which is fine — we lack privileges to actually return a useful answer, but the
call itself should go through.

I didn't touch udevd, which refuses to run if it is not root, and does a lot of
privileged setup, so would refuse to start even if the check was removed.
2026-05-05 17:23:16 +02:00
Lennart Poettering ea07d7fec3 bootctl: allow extra files on 'link' be specified as literal data 2026-05-05 15:09:47 +02:00
Lennart Poettering e7ab31b4d1 bootctl: make sure "unlink" properly tracks "extra" files 2026-05-01 07:10:31 +02:00
Lennart Poettering e48d8a1ea0 bootctl: add "link" command 2026-05-01 07:10:31 +02:00
Lennart Poettering e68bf712be bootctl: rework/modernize "unlink" and add Varlink API for it
Among other things this changes tracking of the location of resources
during GC from using the BootEntrySource enum rather than a path, since
we have that and it is more efficient and easier to grok.
2026-05-01 07:10:31 +02:00
Lennart Poettering 4d0f6ac593 bootctl: add helpers that format a type1 menu entry filename from a commit nr 2026-05-01 07:10:31 +02:00
Lennart Poettering 99ce7a0770 options: get rid of "on_error" parameter to FOREACH_OPTION
I am really not a fan of full code lines passed to macros as parameters.
Let's get rid of the 3rd parameter of FOREACH_OPTION() hence:

1. Let's return errors just as a regular value (though a negative one),
   that can be handled via a OPTION_ERROR case statement for the switch.
   This normalizes handling of the error, just like any other event
   returned by the option parser.

2. In order to avoid exploding the amount of boilerplate in each use
   (that just propagates the error on OPTION_ERROR), let's then
   introduce an explicit FOREACH_OPTION_OR_RETURN(), that returns from
   the calling function on its own (and makes that clear in the name).

Together this cleans up, normalizes the logic and shortens the code.
2026-04-30 11:12:33 +01:00
Daan De Meyer 9d2f5b4611 fundamental/cleanup: add CLEANUP_ELEMENTS() and DEFINE_POINTER_ARRAY_CLEAR_FUNC()
DEFINE_POINTER_ARRAY_CLEAR_FUNC() generates a helper of the form
helper_array_clear(T *array, size_t n) that drops each element but does
not free the array itself, parallel to DEFINE_POINTER_ARRAY_FREE_FUNC()
for cases where the array has automatic storage duration.

CLEANUP_ELEMENTS() pairs with these helpers to provide a _cleanup_-like
attribute for fixed-size arrays: the bound is taken from ELEMENTSOF(),
and the helper is invoked across the elements at scope exit. Compared to
CLEANUP_ARRAY(), the storage is neither freed nor zeroed.

Migrate various logic across the tree over to the new macros.

sd-device: use DEFINE_POINTER_ARRAY_CLEAR_FUNC() for sd_device_unref_array_clear()

Replace the local device_unref_many() helper with the macro-generated
equivalent.

format-table: switch help-table arrays to CLEANUP_ELEMENTS()

Generate table_unref_array_clear() via DEFINE_POINTER_ARRAY_CLEAR_FUNC()
and convert the help-table arrays in bootctl, cryptenroll, nspawn,
repart and vmspawn to CLEANUP_ELEMENTS(). The arrays no longer need a
trailing NULL slot, so the size matches ELEMENTSOF() of the groups
array.

firewall-util: switch netlink message arrays to CLEANUP_ELEMENTS()

Generate sd_netlink_message_unref_array_clear() via
DEFINE_POINTER_ARRAY_CLEAR_FUNC() in place of the NULL-terminated
sd_netlink_message_unref_many(), and convert the two stack arrays of
sd_netlink_message pointers to CLEANUP_ELEMENTS().
2026-04-30 09:15:34 +02:00
Zbigniew Jędrzejewski-Szmek 5ff0ccaf8b tree-wide: change option_parse() to return option and arg via internal state
It was requested to make the 'c', 'opt', and 'arg' params the same, i.e.
defined through the FOREACH_OPTION macro. But we can't do that easily,
because 'c' was defined in the for loop definition, and we can only
define variables of the same type in that way. Also, in some cases we
need only 'c', in other cases with need 'c' and 'arg, in some cases 'c'
and 'opt', and in other cases all three. We'd need to either
conditionalize or mark those variables with _unused_ to deal with
compiler warnings. But a different approach works quite nicely: add
state.opt and state.arg to show the current option and it's argument.
(The short names are picked on purpose to reduce verbosity since those
are used a lot.)
2026-04-27 11:33:10 +02:00
Daan De Meyer 8c3f64e61f tree-wide: Load libcrypto and libssl via dlopen()
Until now OpenSSL was linked into every binary and library that needed
cryptography, pulling libcrypto (and, for resolved, libssl) into the
address space of services that never touch them at runtime. This commit
moves all OpenSSL usage behind the same dlopen helper pattern that we
already use for other optional libraries (libpam, libseccomp, libxz, …)
so libcrypto/libssl are only loaded on demand.

The bulk of the work lives in src/shared/crypto-util.{c,h} (libcrypto)
and src/shared/ssl-util.{c,h} (libssl), which replace the previous
src/shared/openssl-util.{c,h}:

 - crypto-util.{c,h} declares every libcrypto function we call via
   DLSYM_PROTOTYPE() and resolves them inside dlopen_libcrypto().

 - ssl-util.{c,h} holds the libssl-specific DLSYM_PROTOTYPEs,
   dlopen_libssl(), and the SSL_freep cleanup helper, so translation
   units that only need libcrypto do not pull in libssl declarations.

 - Callers refer to the symbols through sym_* aliases rather than the
   original names.

 - Convenience macros that used to be provided by the OpenSSL headers
   (OPENSSL_free, BN_num_bytes, the sk_TYPE_* helpers, …) are
   reimplemented as sym_* wrappers so no code path needs to fall back
   to the linker-resolved symbols.

 - All _cleanup_ helpers are redefined in terms of the sym_* variants
   (EVP_PKEY_freep, X509_freep, BIO_freep, …) so cleanup attributes
   keep working without pulling in libcrypto symbols at link time.

 - The public crypto-util.c entry points (openssl_pubkey_from_pem,
   openssl_digest_many, openssl_hmac_many, openssl_cipher_many,
   kdf_ss_derive, kdf_kb_hmac_derive, rsa_* / ecc_* helpers,
   pubkey_fingerprint, digest_and_sign, pkcs7_new, x509_fingerprint,
   openssl_extract_public_key, pkey_generate_volume_keys, the load_*
   helpers, …) now call dlopen_libcrypto() at entry before touching any
   sym_* pointer.

The call sites across the tree have been converted to call
dlopen_libcrypto()/dlopen_libssl() at the appropriate entry point
before their first sym_* use, and to use sym_* variants throughout:

 - bootctl, sbsign, measure, pcrlock, pcrextend, tpm2-setup, repart,
   cryptsetup, cryptenroll, homectl, homed, homework, keyutil,
   sysupdate, creds, import, dissect-image, pe-binary, pkcs11-util,
   pkcs7-util, tpm2-util, creds-util. resolved additionally dlopens
   libssl for DoT.

The meson build files are updated to depend on libopenssl_cflags (a
new partial dependency that exposes include paths and compile flags
only, not the linker flags) instead of libopenssl for every target that
previously linked against OpenSSL. Nothing links against libcrypto or
libssl directly anymore.

A new src/sbsign/authenticode.c hosts the Authenticode ASN.1 type
definitions that used to live inline in sbsign.c. The OpenSSL
ASN1_SEQUENCE / ASN1_CHOICE / IMPLEMENT_ASN1_FUNCTIONS macros expand to
code that references libcrypto symbols directly, so to keep this
translation unit unlinked from libcrypto we redirect ASN1_item_* to
the sym_* variants via #define and wrap the ASN1_*_it() getters (which
appear as constant function pointers in static initializers) in small
trampoline functions that forward to the sym_* pointers at runtime.

test-dlopen-so gains assertions for dlopen_libcrypto and dlopen_libssl
so the dlopen contract is exercised in CI, and the openssl-specific
test was renamed from test-openssl.c to test-crypto-util.c to match
the new header naming.
2026-04-24 06:32:42 +02:00
Zbigniew Jędrzejewski-Szmek 42506e6dd1 Add 'data' parameter to options and convert to programs where it is useful (#41786) 2026-04-23 21:13:32 +02:00
Zbigniew Jędrzejewski-Szmek b476483639 various: use empty block not break after OPTION_GROUP
Use the same style everywhere.
2026-04-23 19:29:47 +02:00
Zbigniew Jędrzejewski-Szmek 04ad6079bb sbsign: convert to the new option and verb parsers
The options --private-key, --private-key-source, --certificate,
--certificate-source are almost identical in sbsign, but are described
slightly differently. Add OPTION_COMMON_ macros that are parametrized
to keep the purpose of the --private-key and --certificate options
in the description.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 19:13:44 +02:00
Christian Brauner 35a5e10e85 Merge branch 'main' into inode-ref 2026-04-23 19:10:15 +02:00
Lennart Poettering 812aa57d2c string-util: beef up string_is_safe()
This tightens the checks of string_is_safe() and then adds flags to
relax certain aspects of it.

This does alter the rules on certain strings we pass a bit. We mostly
tighten the rules (but I think it's find and good) but we relax them on
others.

I let claude review the changes in behaviour for the various call sites
that I made. It summarized things in this table:

  ╭───────────────────────────────────────────────────┬──────────────────────────────────────────────╮
  │ CALL SITE                                         │ EFFECTIVE DELTA                              │
  ├───────────────────────────────────────────────────┼──────────────────────────────────────────────┤
  │ src/basic/syslog-util  log_namespace_name_valid   │ +UTF-8 required (globs already blocked)      │
  │ src/bootctl  --efi-boot-option-description        │ RELAXED: '\' and quotes now permitted        │
  │ src/core/dbus-manager  pretimeout governor        │ +UTF-8, +no-globs                            │
  │ src/core/load-fragment  ExecStart= path           │ +UTF-8, +no-globs                            │
  │ src/core/main  pretimeout governor (kcmdline)     │ +UTF-8, +no-globs                            │
  │ src/core/service  sd_notify STATUS=               │ +no-globs (ASCII-only preserved)             │
  │ src/home/homectl  --<identity field>=             │ empty now REJECTED; +UTF-8                   │
  │ src/libsystemd-network  dhcp_option_parse_string  │ (equivalent, just explicit)                  │
  │ src/libsystemd-network  sd_dhcp_server boot_fname │ ""→NULL coerced; else equivalent             │
  │ src/libsystemd/journal  SYSLOG_IDENTIFIER fb      │ +UTF-8, +no-globs                            │
  │ src/libsystemd/sd-json  SD_JSON_STRICT strings    │ +UTF-8 required                              │
  │ src/login/logind  session desktop=                │ +UTF-8 required                              │
  │ src/pcrlock  EFI variable string                  │ +UTF-8                                       │
  │ src/pcrlock  EFI action string                    │ RELAXED: empty + '\' now ok; +UTF-8          │
  │ src/resolve  dns-delegate id (from filename)      │ +UTF-8, +no-globs                            │
  │ src/shared/boot-entry  boot_entry_token_valid     │ (equivalent)                                 │
  │ src/shared/conf-parser  section header            │ +UTF-8, +no-globs                            │
  │ src/shared/conf-parser  CONFIG_PARSE_STRING_SAFE  │ +UTF-8 required                              │
  │ src/shared/kbd-util  keymap_is_valid              │ (equivalent; folded into STRING_FILENAME)    │
  │ src/shared/tpm2  nvpcr name                       │ +UTF-8 required                              │
  │ src/shared/vconsole  x11 layout/model/variant/opt │ +UTF-8, +no-globs                            │
  │ src/systemctl  --kernel-cmdline=                  │ +0x7f DEL rejected; empty path split out     │
  │ src/veritysetup  salt=                            │ RELAXED: safety check removed entirely       │
  │ src/vmspawn  --ssh-key-type=                      │ +UTF-8 required                              │
  ╰───────────────────────────────────────────────────┴──────────────────────────────────────────────╯
2026-04-21 17:07:53 +02:00
Daan De Meyer 79862d33a0 chase: add explicit root_fd parameter to chaseat() and drop CHASE_AT_RESOLVE_IN_ROOT
Split the single directory fd that chaseat() used to take into two separate
fds: a root_fd that sets the chroot boundary (symlinks may not escape it,
absolute symlinks resolve relative to it), and a dir_fd that path resolution
starts from. This makes the chroot semantics of chaseat() explicit at every
call site instead of encoding them in the CHASE_AT_RESOLVE_IN_ROOT flag,
which is removed. It also decouples the starting directory from the root
boundary, so callers can descend from any inode inside the tree without
having to reopen the root separately.

XAT_FDROOT passed as root_fd means "no containment" (host root); as dir_fd
it means "start at root_fd". For a smoother transition, AT_FDCWD is also
accepted as root_fd and treated as XAT_FDROOT. When root_fd points to a
directory that is actually the host root, it is normalized to XAT_FDROOT
up front so the existing shortcut path can kick in.

Absolute paths returned by chaseat() are now relative to root_fd, and
relative paths are relative to dir_fd. The result is absolute only when
there is no chroot boundary (root_fd is XAT_FDROOT), or when an absolute
symlink made resolution jump out of the dir_fd subtree; otherwise callers
get a relative path they can feed straight back into an openat()-style
call against dir_fd. Specifically, when dir_fd == root_fd and we're not
operating on the host's root directory, we return a relative path even if
we received an absolute path or resolved an absolute symlink to allow
passing the path directly to openat() style functions. We do this to not
have to go modify every caller of chaseat() to make sure they deal properly
with any absolute paths they might receive. Only when root_fd != dir_fd do
we have to return an absolute path to indicate that the path is relative to
root_fd and not dir_fd.

The shortcut that skips the per-component walk is reworked around a new
chase_xopenat() helper that funnels CHASE_NOFOLLOW, CHASE_MUST_BE_* and
CHASE_TRIGGER_AUTOFS through xopenat_full()'s O_NOFOLLOW, O_DIRECTORY,
XO_REGULAR, XO_SOCKET and XO_TRIGGER_AUTOMOUNT flags. As a result these
flags no longer force us off the shortcut and can be dropped from
CHASE_NO_SHORTCUT_MASK, and the old openat_opath_with_automount() helper
goes away. A CHASE_MUST_BE_ANY alias is introduced for shortcut callers
(stat/access paths) that don't go through xopenat_full() and still need
to bail on those flags locally.

All *_and_* helpers built on top of chaseat() (chase_and_openat,
chase_and_opendirat, chase_and_statat, chase_and_accessat,
chase_and_fopenat_unlocked, chase_and_unlinkat, chase_and_open_parent_at)
gain the same root_fd parameter, and every call site in the tree is
ported to the new signature.

chase_and_open() is also fixed to correctly handle CHASE_EXTRACT_FILENAME
without CHASE_PARENT.
2026-04-20 23:35:31 +02:00
Lennart Poettering 2251f726b3 bootctl: add --print-efi-architecture switch
This is extremely useful for our own test cases, since acquiring the
right EFI architecture string is otherwise a bit nasty.
2026-04-20 22:21:46 +02:00
Lennart Poettering 853d0649d5 find-esp: return pinned fd to ESP/XBOOTLDR
The reworks the ESP/XBOOTLDR logic to pin the ESP/XBOOTLDR via an fd,
and return that as optional return parameter.

So far we only pinned the parent dir of the ESP/XBOOTLDR, which was
useful when verifying that ESP/XBOOTLDR is actually a mount point by
comparing mount ids. This however became obsolete with
a98a6eb95c. Hence, let's clean this up,
and pin the inode we really care about and return it.
2026-04-20 17:19:27 +02:00
Lennart Poettering b54af7ce9a bootctl: make bootspec-util.c independent of bootctl.c
This changes boot_config_load_and_select() to also take the root path as
input, just like the ESP and XBOOTLDR path.

This has the benefit of making the whole file independent of bootctl.c,
which means we can link it into a separate test, and is preparatory work
for a follow-up commit.
2026-04-17 18:52:35 +02:00
Lennart Poettering f85415498c bootctl: drop redundant log message
If unprivileged_mode is false then verify_esp() will treat access errors
like any other and log about them. Here we set it to false, hence
there's no point to log a 2nd time.
2026-04-17 18:52:35 +02:00
Zbigniew Jędrzejewski-Szmek 11505ac135 bootctl: convert options and verbs to the new macros
-RR is formatted using the new OPTION_HELP_ENTRY_VERBATIM so that
we get the same --help as before.

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 13:30:42 +02:00
Lennart Poettering d90d0a1f63 kernel-image: minor refactoring to inspect_kernel()
Let's add make three arguments optional, by splitting inspect_kernel()
from inspect_kernel_full().

Let's also downgrade logging to debug, so that this becomes more
library-like. Let's log on the call-site instead.
2026-04-03 08:15:27 +02:00
Zbigniew Jędrzejewski-Szmek ab3a2f375f sd-varlink: export sd_varlink_set_sentinel
I tried to implement a varlink service using sd-varlink, and
not being able to use the approach with sentinel is exteremely
painful. This is useful internally and likewise externally.
2026-03-29 20:32:15 +02:00
Michael Vogt 777d9c10ad coccinelle: add checks for pointer access without NULL check
The fix in 8f1751a111 made me wonder if we could automatically detect
when pointers are accessed but when this might not be safe. Systemd
is already using a lot of `assert(dst)` and this change now forces
us to use them.

So this commit (ab)uses coccinelle to flag any pointer parameter
dereference not preceded by assert(param), ASSERT_PTR(param), or an
explicit NULL check. It adds integration into meson as a new "coccinelle"
test suite (just like clang-tidy) and is run in CI. The check is not
perfect but seems a reasonable heuristic.

For this RFC commit it is scoped to a subset, it excludes 25 dirs right
now and includes around 100. About 300 warnings left. Busywork that I am
happy to do if there is agreement that it is worth it.

With this in place we would have caught the bug from 8f1751a111 in CI:
```
FAIL: check-pointer-deref.cocci found issues in systemd/src/boot:
diff -u -p systemd/src/boot/measure.c /tmp/nothing/measure.c
--- systemd/src/boot/measure.c
+++ /tmp/nothing/measure.c
@@ -312,7 +312,6 @@ EFI_STATUS tpm_log_tagged_event(
         if (err != EFI_SUCCESS)
                 return err;

-        *ret_measured = true;
         return EFI_SUCCESS;
 }
```

This also adds a new POINTER_MAY_BE_NULL() for the cases when the
called function will do the NULL check (like `iovec_is_set()`).
2026-03-26 18:13:17 +01:00
Lennart Poettering cd911bec6e core: introduce ConditionSecurity=measured-os
So far we always conditioned our TPM magic on the UKI having detected
TPM support in the firmware. This is a bit limiting when we want to
support a software TPM that is not visible to the firmware. Hence let's
split this up, and add a separate control that can be set via the kernel
command line.  However, as before, let's by default inherit the firmare
TPM discovery state into it, to retain the current behaviour unless
overriden.

With this in place, boot with "systemd.tpm2_measured_os=1
systemd.tpm2_software_fallback=1" on the kernel cmdline to get the swtpm
fallback and then a measured OS based on it.
2026-03-26 16:11:34 +01:00
Lennart Poettering 5adfd44c9e copy: add new flags that cause a seek to beginning of files before copying
This is quite useful in various cases where we so far did this manually.
2026-03-23 19:19:46 +00:00
Zbigniew Jędrzejewski-Szmek 31ddd87da0 tree-wide: extend verbs functions with extra per-verb data parameter
We often have a pattern where the same verb function is used for
multiple actions. This leads to an antipattern where we figure out what
action needs to be taken from argv[0] multiple times: often once in
parse_argv() to figure out what options are allowed, then once again
implicitly in dispatch_verb(), and then again in the action verb itself.
Let's allow passing a parameter into the verb to simplify this.

This matches a pattern we have in conf-parser.h, where we have both
void *userdata (more global) and void *data (per-config item). Here,
I opted for uintptr_t userdata. It seems that most of the time we'll
want to just pass an enum value. This works OK with no casts. I also
tried a void* and union. In both cases, much more boilerplate is needed:
either a cast or a macro to help avoid compiler warnings. uintptr_t
seems generic enough to cover foreseeable usecases with no fuss.

This is a noop refactoring. See next commit for an example.
2026-03-18 10:28:47 +00:00
Lennart Poettering 8a2c423870 find-esp: introduce _full() flavour of ESP/XBOOTLDR discovery functions
These functions take so many return paramaters, and in many of our cases
we don't actually needt them. Hence introduce _full() flavours of the
funcs, and hide the params by default.
2026-03-18 10:25:59 +00:00
Mike Yuan 192954ac68 bootctl: declare missing arg_* in header
Follow-up for 90cf998875
2026-03-04 14:32:15 +01:00
Yu Watanabe 4b4eba1666 tree-wide: use _contains() rather than _get()/_find() 2026-03-02 23:10:22 +09:00
Zbigniew Jędrzejewski-Szmek 04897fbbee bootctl: override is_efi_boot() check by --variables= option (#40413)
Fixes #40392.
2026-02-25 15:42:53 +01:00
Mike Yuan 577e5e9a5e parse-argument: make parse_tristate_argument() do something useful
I expressed the issue I have with parse_tristate_argument()
in #37751: it doesn't add any value to direct use of parse_tristate();
on the contrary, it doesn't support means to reset the arg to "auto"/-1 state.
The mere reason it existed is that we need a int type ret param.

Since the previous attempt to address this mess failed, let's
try to make the function more useful by making it accept "auto".
I figure this is useful on its own.

As requested in
https://github.com/systemd/systemd/pull/40652#discussion_r2831833996,
the function name is suffixed with _with_auto() to establish
that "auto" is handled internally.
2026-02-20 21:20:45 +01:00
r-vdp 450e0dce02 systemd-boot: add a preferred setting that's similar to default but avoids booting known-bad entries
Motivation:
Currently, when setting the default boot pattern, boot assessment status
is not taken into account. This means that with boot assessment enabled,
when an explicit boot entry is configured as the default entry using an
EFI var, as is common for instance in A/B boot schemes, the configured
entry will be booted indefinitly, regardless of the entry's boot
assessment status.
In order to allow for this use case in combination with boot assessment,
we introduce a new `preferred` keyword, both in the config file and in the
bootctl CLI, that acts very similar to the existing `default` keyword but
takes boot assessment into account and never selects any entries that
have been marked as bad.
If the preferred pattern does not resolve to any bootable entry, and a
default pattern is also specified, then the default pattern will be
considered next, and we may then still select a known-bad entry to be
booted.

Fixes: https://github.com/systemd/systemd/issues/31215
Fixes: https://github.com/systemd/systemd/issues/40192
2026-02-18 03:28:12 +09:00
Yu Watanabe ed6a2eaa31 ask-password-api: several modernizations for ask_password_agent(); use CLEANUP_TMPFILE_AT more (#40631) 2026-02-16 20:07:32 +09:00
Mike Yuan 09388a6b9e tree-wide: drop redundant check for SD_VARLINK_METHOD_MORE flag
If the IDL declares the method requires 'more' yet the call doesn't
have it set, varlink_idl_validate_method_call() should have rejected
it and the callback shouldn't be reached.
2026-02-16 09:44:54 +01:00
Yu Watanabe 07f147d544 bootctl: do not use the EFI path as XBOOTLDR path
When running in a container, EFI and XBOOTLDR partition check is
relaxed, hence /boot may be recognized as both EFI and XBOOTLDR
partition.

Before:
```
$ run0 systemd-nspawn -xD / --private-network --bind=/sys/firmware/efi/efivars --bind=/boot -E SYSTEMD_LOG_LEVEL=debug -- build/bootctl --variables=yes --no-pager -x
Failed to check file system type of "/efi": No such file or directory
Using EFI System Partition at /boot.
Using XBOOTLDR partition at /boot as $BOOT.
/boot
```

After:
```
$ run0 systemd-nspawn -xD / --private-network --bind=/sys/firmware/efi/efivars --bind=/boot -E SYSTEMD_LOG_LEVEL=debug -- build/bootctl --variables=yes -x
Failed to check file system type of "/efi": No such file or directory
Using EFI System Partition at /boot.
Didn't find an XBOOTLDR partition, using the ESP as $BOOT.
/boot
```
2026-02-13 16:11:33 +09:00
Yu Watanabe 9bc1336abd bootctl: do not show an empty () for ESP partition
Before:
```
$ run0 systemd-nspawn -xD / --private-network --bind=/sys/firmware/efi/efivars --bind=/boot -- build/bootctl --variables=yes --no-pager
(snip)
Boot Loader Entry Locations:
          ESP: /boot ()
       config: /boot//loader/loader.conf
     XBOOTLDR: /boot ($BOOT)
        token: fedora
(snip)
```

After:
```
run0 systemd-nspawn -xD / --private-network --bind=/sys/firmware/efi/efivars --bind=/boot -- build/bootctl --variables=yes --no-pager
(snip)
Boot Loader Entry Locations:
          ESP: /boot
       config: /boot//loader/loader.conf
     XBOOTLDR: /boot ($BOOT)
        token: fedora
(snip)
```

This also moves spurious position of new line in each output.
2026-02-13 16:11:33 +09:00
Yu Watanabe 340c82c454 bootctl: make list command take --variables= option 2026-02-13 16:11:33 +09:00
Yu Watanabe 865f0fe28f bootctl: make status command take --variables= option 2026-02-13 16:11:33 +09:00
Yu Watanabe 6cd57ebcef bootctl: make reboot-to-firmware command take --variables= option 2026-02-13 16:11:33 +09:00
Yu Watanabe 1fa1e88ead bootctl: override is_efi_boot() check if --variables= option is specified
Fixes #40392.
2026-02-13 16:11:33 +09:00
Yu Watanabe 28fa318b16 bootctl: move arg_touch_variables checkers to bootctl-util.c
No functional change, just refactoring.
2026-02-13 16:11:30 +09:00
Yu Watanabe 3c5ed73030 bootctl: refuse --variables=yes when EFI support is disabled 2026-02-13 16:08:23 +09:00
Daan De Meyer 4f5d44ef53 tree-wide: Migrate to varlink_set_sentinel() 2026-02-11 14:25:36 +01:00