1
0
mirror of https://github.com/systemd/systemd synced 2025-11-17 07:44:46 +01:00

Compare commits

...

30 Commits

Author SHA1 Message Date
Yu Watanabe
ee3cd7890d
Several cleanups for libcryptsetup dependency (#39452) 2025-11-02 08:07:15 +09:00
Lennart Poettering
d714edd26c
repart: varlink support (#39421)
Split out of #38764

Replaces: #33741
2025-11-01 23:21:37 +01:00
Christoph Anton Mitterer
a983cf253f doc: indicate Type=oneshot also detects invocation failures
Type `simple` explicitly mentions that invocation failures like a missing binary
or `User=` name won’t get detected – whereas type `exec` mentions that it does.

Type `oneshot` refers to being similar to `simple`, which could lead one to
assume it doesn’t detect such invocation failures either – it seems however it
does.

Indicate this my changing its wording to be similar to `exec`.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2025-11-01 22:48:28 +01:00
Lennart Poettering
d1aa3860b2 ci: add testcases for recently added stuff 2025-11-01 22:01:35 +01:00
Lennart Poettering
5f076e44fe repart: report vendor/model/subsystem fields in ListCandidateDevices
Prompted by: #39435
2025-11-01 22:01:35 +01:00
Lennart Poettering
ea94a05f8a blockdev-list: switch to log_device_xyz() style logging 2025-11-01 22:01:35 +01:00
Lennart Poettering
2103067f25 udev: introduce ID_BLOCK_SUBSYSTEM property
Virtual block devices are a bit weird: they have no parent device, and
thus cannot be related to the subsystem they belong to, except by
pattern matching their name. This is OK to do if one knows what to look
for. However for tools that do not want to carry a list of known
subsystems with their appropriate matching patters this sucks. Let's
introduce a new ID_BLOCK_SUBSYSTEM property we can set on block devices
that carries an explicit string for this. Do so for a small number of
key subsystems: DM, loopback and zram.
2025-11-01 22:01:35 +01:00
Lennart Poettering
63b9c8611d repart: sort input before output parameters in varlink IDL 2025-11-01 22:01:35 +01:00
Lennart Poettering
0f9d58cc36 repart: add knobs for automatically deferring all partitions marked as empty or for factory reset 2025-11-01 22:01:35 +01:00
Lennart Poettering
1c76e204d3 repart: send out progress information via varlink (if more flag is given)
And while we are at it, also send it out via sd_notify()
2025-11-01 22:01:35 +01:00
Lennart Poettering
15734190c7 repart: add Varlink call that runs repart's engine 2025-11-01 22:01:34 +01:00
Lennart Poettering
2ecfea7491 repart: if device node is specified as "-", calculate needed disk space
So far repart always required specification of a device node. And if
none was specified, then we'd fine the node backing the root fs. Let's
optionally allow that the device node is explicitly not specified (i.e.
specified as "-" or ""), in which case we'll just print the size of the
minimal image given the definitions.
2025-11-01 22:00:47 +01:00
Lennart Poettering
0eab6d2960 repart: split out main function that ponders about placement of partitions
Let's move the key code that places partitions into a function of its
own. That will make it easier to call this via varlink.
2025-11-01 21:58:28 +01:00
Lennart Poettering
a47cbb6d9d repart: move definitions + dry_run + empty fields into Context
This is preparation for making this eventually available via Varlink,
where we'd like to create Context object for each call that we can free
once it is done, but not inherit state from an earlier call.

Also fixes a couple of cases where we accessed arg_node, but where we
should have accessed the Context-specific copy in .node.
2025-11-01 21:58:28 +01:00
Lennart Poettering
eccd8d9a57 repart: use SD_JSON_BUILD_UNSIGNED for disk sizes, as we should 2025-11-01 21:58:28 +01:00
Lennart Poettering
b64eb98054 sd-varlink: fix sd_varlink_collect() with empty replies
Follow-up for: 48c64813ec6bdbe536b7a62281292ea5981295ba
2025-11-01 21:58:28 +01:00
Lennart Poettering
633a4b8839 man: add documentation for the various sd_json_dispatch_xyz() calls
Now that we comprehensively return accept null it's a good idea to
document which function maps null to what.
2025-11-01 21:58:28 +01:00
Yu Watanabe
db1f63463a cryptsetup-util: sym_crypt_free() and friends are unused when libcryptsetup is disabled 2025-11-02 05:50:31 +09:00
Yu Watanabe
6afaa7fb3a cryptsetup-util: sort loaded function prototypes 2025-11-02 05:50:31 +09:00
Yu Watanabe
f8c33b1274 libcryptsetup: drop several unnecessary checks for existences of functions by libcryptsetyp
The functions crypt_set_metadata_size() and friends are supported since
libcryptsetup-2.0.

This also merges checks for functions used for supporting libcryptsetup
plugins with others.
Moreover, check existence of one more function (crypt_logf) that is used in
libcryptsetup plugins.
2025-11-02 05:49:29 +09:00
Lennart Poettering
93317e9c17 sd-json: parse signals also in string format 2025-11-01 21:43:37 +01:00
Lennart Poettering
786aaed943 sd-json: parse uid_t/gid_t as uint32_t first
Let's use the proper uint32_t parsers initially, so that the usual logic
of formatting integers as decimal strings, works too for uids/gids. Not
because it made any sense to encode them like that, but just to be
systematic here.
2025-11-01 21:43:37 +01:00
Lennart Poettering
e01f8990f1 sd-json: make sure all dispatch helpers do something sensible in case of "null" JSON value
Most of our dispatch helpers already do something useful in case they
are invoked on a null JSON value: they translate this to the appropriate
niche value for the type, if there is one.

Add the same for *all* dispatchers we have, to make this fully
systematic.

For various types it's not always clear which niche value to pick. I
opted for UINT{8,16,32,64}_MAX for the various unsigned integers, which
maps our own use in most cases. I opted for -1 for the various signed
integer types. For arrays/blobs of stuff I opted for the empty
array/blob, and for booleans I opted for false.

Of course, in various cases this is not going to be the right niche
value, but that's entirely fine, after all before a json value reaches a
dispatcher function it must pass one of two type checks first:

1. Either the .type field of sd_json_dispatch_field must be
   _SD_JSON_VARIANT_TYPE_INVALID to not do a type check at all

2. Or the .type field is set, but then the SD_JSON_NULLABLE flag must be
   set in .flags.

This means, accidentally generating the niche values on null is not
really likely.
2025-11-01 21:43:37 +01:00
Yu Watanabe
3cc3b469cc
Ignore --now when systemctl enable is called in a chroot (#39456) 2025-11-02 04:48:53 +09:00
Daan De Meyer
10e82fde7b parse-util: Add parse_capability_set()
Let's extract common capability parsing code into a generic function
parse_capability_set() with a comprehensive set of unit tests.

We also replace usages of UINT64_MAX with CAP_MASK_UNSET where
applicable and replace the default value of CapabilityBoundingSet
with CAP_MASK_ALL which more clearly identifies that it is initialized
to all capabilities.

AI (copilot) was used to extract the generic function and write the
unit tests, with manual review and fixing afterwards to make sure
everything was correct.
2025-11-02 04:47:21 +09:00
Daan De Meyer
1a3b3c57c6 test: migrate test-load-fragment to use ASSERT_* macros
Replace all assert_se() calls with appropriate ASSERT_* macros from tests.h:
- assert_se(r >= 0) → ASSERT_OK(r)
- assert_se(r == 0) → ASSERT_OK_ZERO(r)
- assert_se(r == -ERR) → ASSERT_ERROR(r, ERR)
- assert_se(expr == value) → ASSERT_EQ(expr, value)
- assert_se(str1, str2) → ASSERT_STREQ(str1, str2)
- assert_se(ptr) → ASSERT_NOT_NULL(ptr)
- assert_se(!ptr) → ASSERT_NULL(ptr)
- assert_se(expr) → ASSERT_TRUE(expr)
- assert_se(!expr) → ASSERT_FALSE(expr)

Also added unsigned suffixes (U) to numeric literals in comparisons with
unsigned types (size_t, rlim_t) to eliminate signedness warnings.

This code was written with the help of AI.
2025-11-02 04:47:21 +09:00
Luca Boccassi
10fc43e504 test: add test case for verity deferred removal without sharing
I recently found out (the hard way) that on an older version
there was a bug when the verity sharing is disabled: the
deferred close flag was not set correctly, so verity devices
were leaked.

This is not an issue in main currently, but add a test case
to cover it just in case, to avoid future regressions.
2025-11-02 04:43:06 +09:00
Lennart Poettering
7517e41a49 resolvectl: do not use strjoina() on user provided strings 2025-11-02 04:41:07 +09:00
Zbigniew Jędrzejewski-Szmek
77a1cc8fa0 systemctl: downgrade or silence warnings for --now
When calling systemctl enable/disable/reenable --now, we'd always fail with
error when operating offline. This seemly overly restricitive. In particular,
if systemd is not running at all, the service is not running either, so
complaining that we can't stop it is completely unnecessary. But even when
operating in a chroot where systemd is not running, let's just emit a warning
and return success. It's fairly common to have installation or package scripts
which do such calls and not starting/restarting the service in those scenarios
is the desired and expected operation. (If --now is called in combination
with --global or --root=, keep returning an error.)

Also make the messages nicer. I was adding some docs to tell the user to run
'systemctl enable --now', and checked how the command can fail, and the error
message that the user might see in some common scenarios was too complicated.
Split it up to be nicer.
2025-11-01 10:25:39 +01:00
Zbigniew Jędrzejewski-Szmek
0ff5985176 systemctl: convert return value of install_client_side() to enum
The checks are reordered to do checks that don't require interacting with the
system first.
2025-11-01 10:25:04 +01:00
45 changed files with 2157 additions and 903 deletions

View File

@ -828,6 +828,29 @@ manpages = [
'sd_journal_seek_tail'], 'sd_journal_seek_tail'],
''], ''],
['sd_journal_stream_fd', '3', ['sd_journal_stream_fd_with_namespace'], ''], ['sd_journal_stream_fd', '3', ['sd_journal_stream_fd_with_namespace'], ''],
['sd_json_dispatch_string',
'3',
['sd_json_dispatch_const_string',
'sd_json_dispatch_double',
'sd_json_dispatch_id128',
'sd_json_dispatch_int16',
'sd_json_dispatch_int32',
'sd_json_dispatch_int64',
'sd_json_dispatch_int8',
'sd_json_dispatch_intbool',
'sd_json_dispatch_signal',
'sd_json_dispatch_stdbool',
'sd_json_dispatch_strv',
'sd_json_dispatch_tristate',
'sd_json_dispatch_uid_gid',
'sd_json_dispatch_uint16',
'sd_json_dispatch_uint32',
'sd_json_dispatch_uint64',
'sd_json_dispatch_uint8',
'sd_json_dispatch_unsupported',
'sd_json_dispatch_variant',
'sd_json_dispatch_variant_noref'],
''],
['sd_listen_fds', ['sd_listen_fds',
'3', '3',
['SD_LISTEN_FDS_START', 'sd_listen_fds_with_names'], ['SD_LISTEN_FDS_START', 'sd_listen_fds_with_names'],

View File

@ -0,0 +1,364 @@
<?xml version='1.0'?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="sd_json_dispatch_string" xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>sd_json_dispatch_string</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>sd_json_dispatch_string</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>sd_json_dispatch_string</refname>
<refname>sd_json_dispatch_const_string</refname>
<refname>sd_json_dispatch_strv</refname>
<refname>sd_json_dispatch_stdbool</refname>
<refname>sd_json_dispatch_intbool</refname>
<refname>sd_json_dispatch_tristate</refname>
<refname>sd_json_dispatch_variant</refname>
<refname>sd_json_dispatch_variant_noref</refname>
<refname>sd_json_dispatch_int64</refname>
<refname>sd_json_dispatch_int32</refname>
<refname>sd_json_dispatch_int16</refname>
<refname>sd_json_dispatch_int8</refname>
<refname>sd_json_dispatch_uint64</refname>
<refname>sd_json_dispatch_uint32</refname>
<refname>sd_json_dispatch_uint16</refname>
<refname>sd_json_dispatch_uint8</refname>
<refname>sd_json_dispatch_double</refname>
<refname>sd_json_dispatch_uid_gid</refname>
<refname>sd_json_dispatch_id128</refname>
<refname>sd_json_dispatch_signal</refname>
<refname>sd_json_dispatch_unsupported</refname>
<refpurpose>Decode JSON variant values and write them to the specified memory</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-varlink.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_string</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_const_string</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_strv</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_stdbool</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_intbool</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_tristate</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_variant</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_variant_noref</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_int64</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_int32</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_int16</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_int8</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_uint64</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_uint32</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_uint16</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_uint8</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_double</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_uid_gid</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_id128</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_signal</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_json_dispatch_unsupported</function></funcdef>
<paramdef>const char *<parameter>name</parameter></paramdef>
<paramdef>sd_json_variant *<parameter>variant</parameter></paramdef>
<paramdef>sd_dispatch_flags <parameter>flags</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>The various functions described here are intended for use in the
<type>sd_json_dispatch_field</type> structure arrays the
<citerefentry><refentrytitle>sd_json_dispatch</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
<citerefentry><refentrytitle>sd_varlink_dispatch</refentrytitle><manvolnum>3</manvolnum></citerefentry>
functions accept; they decode the provided JSON variant object's value, and write it to the memory
indicated by the <parameter>userdata</parameter> pointer. The <parameter>name</parameter> parameter
contains the field name (in the JSON object it is contained in) of the value being decoded. For details
on the <parameter>flags</parameter> parameter see the <function>sd_json_dispatch()</function>
documentation.</para>
<para>Note that all these functions not only accept the native JSON type they are intended for, but also
accept null JSON values, in which case they assign an appropriate invalid/unset/null value, as
appropriate for the type (for details see below).</para>
<para><function>sd_json_dispatch_string()</function> decodes a JSON string value, and allocates a
<constant>NUL</constant> terminated copy in dynamic memory. The <parameter>userdata</parameter> pointer
must point to a pointer to a string, which is freed if non-<constant>NULL</constant>, and then replaced
by the newly allocated one. If a JSON null value is passed, the existing string is freed and
<constant>NULL</constant> is assigned.</para>
<para><function>sd_json_dispatch_const_string()</function> is very similar to
<function>sd_json_dispatch_string()</function>, but does not allocate a string in dynamic
memory. Instead, it just writes a pointer into the JSON object into the indicated memory (or
<constant>NULL</constant> in case a JSON null object is passed). The memory remains valid only as long as
the indicated variant object is kept allocated (which can happen via direct reference, or via an indirect
one via an object that references the specified variant). The memory <parameter>userdata</parameter>
points to on input is <emphasis>not</emphasis> freed before the new value is assigned.</para>
<para><function>sd_json_dispatch_stdbool()</function> and <function>sd_json_dispatch_intbool()</function>
decode JSON boolean values and write them to the indicated memory. The former expects a variable of the
C99 <type>bool</type> type in the indicated memory, the latter an <type>int</type> (which will only
receive the values 0 and 1). The JSON null value is treated equivalent to a JSON false.</para>
<para><function>sd_json_dispatch_tristate()</function> is very similar
to<function>sd_json_dispatch_intbool()</function>, but will assign -1 if a JSON null value is passed. Or
in other words, the integer will have a value &gt; 0, == 0 or &lt; 0, for the cases true, false or
invalid/unset/null.</para>
<para><function>sd_json_dispatch_variant()</function> takes an additional reference to the passed JSON
object (via <function>sd_json_variant_ref()</function>) and writes the pointer to the indicated
memory. No decoding is done. If the indicated pointer is non-<constant>NULL</constant> on input it is
freed (via <function>sd_json_variant_unref()</function>) before the new pointer is written.</para>
<para><function>sd_json_dispatch_variant_noref()</function> is similar, but does <emphasis>not</emphasis>
take a new reference to the JSON variant object. The pointer hence only remains valid as long as the
original object stays referenced. If the indicated pointer is non-<constant>NULL</constant> on input it
is <emphasis>not</emphasis> freed before the new pointer is written.</para>
<para>The <function>sd_json_dispatch_int64()</function>, <function>sd_json_dispatch_int32()</function>,
<function>sd_json_dispatch_int16()</function>, <function>sd_json_dispatch_int8()</function>,
<function>sd_json_dispatch_uint64()</function>, <function>sd_json_dispatch_uint32()</function>,
<function>sd_json_dispatch_uint16()</function> and <function>sd_json_dispatch_uint8()</function>
functions decode a JSON integer value, and write the value to the indicated memory. The function names
indicate the word width and signedness of the integers being parsed. If the JSON null value is passed the
functions for the unsigned integer types will assign the maximum value the type takes
(i.e. <constant>UINT64_MAX</constant>, <constant>UINT32_MAX</constant> …), and the signed versions assign
-1. Instead of a JSON integer value these functions also accept JSON strings that contain formatted
decimal numbers, in order to improve compatibility for encoding integer values that cannot be represented
in 64bit double precision floating point numbers in other programming languages that encode JSON numerals
this way.</para>
<para>The <function>sd_json_dispatch_double()</function> function decodes a 64bit double precision
floating point number. If a JSON null value is passed, assigns NaN.</para>
<para>The <function>sd_json_dispatch_uid_gid()</function> function is similar to
<function>sd_json_dispatch_uint32()</function>, and is intended to decode 32bit UNIX UID/GID numbers, as
used on Linux. It will decode a JSON null value as 4294967295 (i.e. <literal>(uid_t) -1</literal>), and
will refuse the values 65535 and 4294967295 when passed as JSON numerals (i.e. both the 16bit and 32bit
"invalid" UID/GID, as these values have special meaning for various UNIX syscalls, on different OSes and
file systems).</para>
<para><function>sd_json_dispatch_id128()</function> decodes a 128bit ID formatted as a JSON string. It
supports both RFC9562 UUID formatting, as well as 64 hexadecimal characters without separators, the same
way as
<citerefentry><refentrytitle>sd_id128_from_string</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If
the JSON null value is passed, the all-zero ID is assigned.</para>
<para><function>sd_json_dispatch_signal()</function> decodes a UNIX process signal specification. It
expects either an JSON string containing a signal name such as <literal>SIGINT</literal> or
<literal>SIGTERM</literal>, or an unsigned JSON integer value with the signal number (in the Linux
definition). The indicated memory must point to an <type>int</type> variable to write the signal number
to. If the JSON null value is passed a negative value will be written to the memory.</para>
<para><function>sd_json_dispatch_unsupported()</function> will always fail with the
-<constant>EINVAL</constant> error.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
<para>On success, these functions return a non-negative integer. On failure, they return a negative
errno-style error code.</para>
<refsect2>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An argument is invalid.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect2>
</refsect1>
<xi:include href="libsystemd-pkgconfig.xml" />
<refsect1>
<title>History</title>
<para>
<function>sd_json_dispatch_string()</function>, <function>sd_json_dispatch_const_string()</function>,
<function>sd_json_dispatch_strv()</function>, <function>sd_json_dispatch_stdbool()</function>,
<function>sd_json_dispatch_intbool()</function>, <function>sd_json_dispatch_tristate()</function>,
<function>sd_json_dispatch_variant()</function>, <function>sd_json_dispatch_variant_noref()</function>,
<function>sd_json_dispatch_int64()</function>, <function>sd_json_dispatch_int32()</function>,
<function>sd_json_dispatch_int16()</function>, <function>sd_json_dispatch_int8()</function>,
<function>sd_json_dispatch_uint64()</function>, <function>sd_json_dispatch_uint32()</function>,
<function>sd_json_dispatch_uint16()</function>, <function>sd_json_dispatch_uint8()</function>,
<function>sd_json_dispatch_double()</function>, <function>sd_json_dispatch_uid_gid()</function>,
<function>sd_json_dispatch_id128()</function>, <function>sd_json_dispatch_signal()</function>,
<function>sd_json_dispatch_unsupported()</function> were added in version 257.</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-json</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-varlink</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd_json_dispatch</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd_variant_dispatch</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -26,7 +26,7 @@
<cmdsynopsis> <cmdsynopsis>
<command>systemd-repart</command> <command>systemd-repart</command>
<arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="repeat"><replaceable><optional>BLOCKDEVICE</optional></replaceable></arg> <arg choice="opt">BLOCKDEVICE</arg>
</cmdsynopsis> </cmdsynopsis>
<para><filename>systemd-repart.service</filename></para> <para><filename>systemd-repart.service</filename></para>
@ -35,10 +35,10 @@
<refsect1> <refsect1>
<title>Description</title> <title>Description</title>
<para><command>systemd-repart</command> creates partition tables, and adds or grows partitions, <para><command>systemd-repart</command> creates partition tables, and adds or grows partitions, based on
based on the configuration files described in the configuration files described in
<citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>. <citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>. It operates
</para> on the block device or file image specified on the command line.</para>
<para><command>systemd-repart</command> is used when <emphasis>building</emphasis> OS images, and also <para><command>systemd-repart</command> is used when <emphasis>building</emphasis> OS images, and also
when <emphasis>deploying</emphasis> images to automatically adjust them, during boot, to the system they when <emphasis>deploying</emphasis> images to automatically adjust them, during boot, to the system they
@ -53,6 +53,11 @@
<filename>systemd-repart.service</filename> service is generally run at boot in the initrd, in order to <filename>systemd-repart.service</filename> service is generally run at boot in the initrd, in order to
augment the partition table of the OS before its partitions are mounted.</para> augment the partition table of the OS before its partitions are mounted.</para>
<para>If the block device is specified as <literal>-</literal> (or as an empty string),
<command>systemd-repart</command> will not operate on any block device or image file, and instead
determine and output the minimum disk/image size for the specified partition configuration, taking all
configured size constraints into account.</para>
<para><command>systemd-repart</command> operations are mostly incremental: it grows existing partitions <para><command>systemd-repart</command> operations are mostly incremental: it grows existing partitions
or adds new ones, but does not shrink, delete, or move existing partitions. The service is intended to be or adds new ones, but does not shrink, delete, or move existing partitions. The service is intended to be
run on every boot, but when it detects that the partition table already matches the installed run on every boot, but when it detects that the partition table already matches the installed
@ -495,6 +500,30 @@
<xi:include href="version-info.xml" xpointer="v253"/></listitem> <xi:include href="version-info.xml" xpointer="v253"/></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--defer-partitions-empty=yes</option></term>
<listitem><para>This is very similar to <option>--defer-partitions=</option> but automatically
selects all partitions for deferral that have <option>Format=empty</option> set. It may be used in
conjunction with <option>--defer-partitions=</option> or
<option>--defer-partitions-factory-reset=yes</option>, in which case all matching partitions are
deferred.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--defer-partitions-factory-reset=yes</option></term>
<listitem><para>This is very similar to <option>--defer-partitions=</option> but automatically
selects all partitions for deferral that have <option>FactoryReset=yes</option> set. It may be used
in conjunction with <option>--defer-partitions=</option> or
<option>--defer-partitions-empty=yes</option>, in which case all matching partitions are
deferred.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>--sector-size=<replaceable>BYTES</replaceable></option></term> <term><option>--sector-size=<replaceable>BYTES</replaceable></option></term>

View File

@ -206,7 +206,7 @@
identify the main process of the service. The manager will proceed with starting follow-up units identify the main process of the service. The manager will proceed with starting follow-up units
after the parent process exits.</para></listitem> after the parent process exits.</para></listitem>
<listitem><para>Behavior of <option>oneshot</option> is similar to <option>simple</option>; <listitem><para>Behavior of <option>oneshot</option> is similar to <option>exec</option>;
however, the service manager will consider the unit up after the main process exits. It will then however, the service manager will consider the unit up after the main process exits. It will then
start follow-up units. <varname>RemainAfterExit=</varname> is particularly useful for this type start follow-up units. <varname>RemainAfterExit=</varname> is particularly useful for this type
of service. <varname>Type=</varname><option>oneshot</option> is the implied default if neither of service. <varname>Type=</varname><option>oneshot</option> is the implied default if neither

View File

@ -1247,53 +1247,30 @@ libcryptsetup = dependency('libcryptsetup',
libcryptsetup_cflags = libcryptsetup.partial_dependency(includes: true, compile_args: true) libcryptsetup_cflags = libcryptsetup.partial_dependency(includes: true, compile_args: true)
have = libcryptsetup.found() have = libcryptsetup.found()
foreach ident : ['crypt_set_metadata_size', conf.set10('HAVE_LIBCRYPTSETUP', have)
'crypt_activate_by_signed_key',
'crypt_token_max', foreach ident : [
'crypt_reencrypt_init_by_passphrase', 'crypt_activate_by_token_pin', # 2.4
'crypt_reencrypt', 'crypt_logf', # 2.4
'crypt_reencrypt_run', 'crypt_reencrypt_run', # 2.4
'crypt_set_data_offset', 'crypt_token_external_path', # 2.4
'crypt_set_keyring_to_link', 'crypt_token_max', # 2.4
'crypt_resume_by_volume_key', 'crypt_set_keyring_to_link', # 2.7
'crypt_token_set_external_path'] 'crypt_token_set_external_path', # 2.7
]
have_ident = have and cc.has_function( have_ident = have and cc.has_function(
ident, ident,
prefix : '#include <libcryptsetup.h>', prefix : '#include <libcryptsetup.h>',
# crypt_reencrypt() raises a deprecation warning so make sure -Wno-deprecated-declarations is
# specified otherwise we fail to detect crypt_reencrypt() if -Werror is used.
args : '-Wno-deprecated-declarations',
dependencies : libcryptsetup) dependencies : libcryptsetup)
conf.set10('HAVE_' + ident.to_upper(), have_ident) conf.set10('HAVE_' + ident.to_upper(), have_ident)
endforeach endforeach
conf.set10('HAVE_LIBCRYPTSETUP', have)
if meson.version().version_compare('>=1.3.0') conf.set10('HAVE_LIBCRYPTSETUP_PLUGINS',
have = (cc.has_function( libcryptsetup_plugins.allowed() and
'crypt_activate_by_token_pin', conf.get('HAVE_CRYPT_ACTIVATE_BY_TOKEN_PIN') == 1 and
prefix : '#include <libcryptsetup.h>', conf.get('HAVE_CRYPT_LOGF') == 1 and
dependencies : libcryptsetup, conf.get('HAVE_CRYPT_TOKEN_EXTERNAL_PATH') == 1)
required : libcryptsetup_plugins) and
cc.has_function(
'crypt_token_external_path',
prefix : '#include <libcryptsetup.h>',
dependencies : libcryptsetup,
required : libcryptsetup_plugins))
else
if libcryptsetup_plugins.allowed()
have = (cc.has_function(
'crypt_activate_by_token_pin',
prefix : '#include <libcryptsetup.h>',
dependencies : libcryptsetup) and
cc.has_function(
'crypt_token_external_path',
prefix : '#include <libcryptsetup.h>',
dependencies : libcryptsetup))
else
have = false
endif
endif
conf.set10('HAVE_LIBCRYPTSETUP_PLUGINS', have)
libcurl = dependency('libcurl', libcurl = dependency('libcurl',
version : '>= 7.32.0', version : '>= 7.32.0',
@ -1589,8 +1566,7 @@ conf.set10('ENABLE_IMPORTD', have)
have = get_option('homed').require( have = get_option('homed').require(
conf.get('HAVE_OPENSSL') == 1 and conf.get('HAVE_OPENSSL') == 1 and
conf.get('HAVE_LIBFDISK') == 1 and conf.get('HAVE_LIBFDISK') == 1 and
conf.get('HAVE_LIBCRYPTSETUP') == 1 and conf.get('HAVE_LIBCRYPTSETUP') == 1,
conf.get('HAVE_CRYPT_RESUME_BY_VOLUME_KEY') == 1,
error_message : 'openssl, fdisk and libcryptsetup required').allowed() error_message : 'openssl, fdisk and libcryptsetup required').allowed()
conf.set10('ENABLE_HOMED', have) conf.set10('ENABLE_HOMED', have)

View File

@ -14,3 +14,11 @@ ACTION!="remove", SUBSYSTEM=="block", \
# Reset access rights to each loopback device once it gets detached. # Reset access rights to each loopback device once it gets detached.
ACTION=="change", SUBSYSTEM=="block", KERNEL=="loop*", ENV{DISK_MEDIA_CHANGE}=="1", TEST!="loop/backing_file", GROUP="disk", MODE="660" ACTION=="change", SUBSYSTEM=="block", KERNEL=="loop*", ENV{DISK_MEDIA_CHANGE}=="1", TEST!="loop/backing_file", GROUP="disk", MODE="660"
# Provide a somewhat cleaned up field indicating the subsystem various
# 'virtual' block devices belong too, in order to avoid replicating name based
# pattern matching in every consumer
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="dm-*", ENV{ID_BLOCK_SUBSYSTEM}="dm"
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="loop*", ENV{ID_BLOCK_SUBSYSTEM}="loop"
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="md*", ENV{ID_BLOCK_SUBSYSTEM}="md"
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="zram*", ENV{ID_BLOCK_SUBSYSTEM}="zram"

View File

@ -13,6 +13,7 @@
#include "bus-map-properties.h" #include "bus-map-properties.h"
#include "bus-unit-util.h" #include "bus-unit-util.h"
#include "bus-util.h" #include "bus-util.h"
#include "capability-util.h"
#include "copy.h" #include "copy.h"
#include "env-util.h" #include "env-util.h"
#include "fd-util.h" #include "fd-util.h"
@ -135,7 +136,7 @@ static SecurityInfo *security_info_new(void) {
*info = (SecurityInfo) { *info = (SecurityInfo) {
.default_dependencies = true, .default_dependencies = true,
.capability_bounding_set = UINT64_MAX, .capability_bounding_set = CAP_MASK_ALL,
.restrict_namespaces = UINT64_MAX, .restrict_namespaces = UINT64_MAX,
._umask = 0002, ._umask = 0002,
}; };

View File

@ -7,6 +7,8 @@
#include <sys/socket.h> #include <sys/socket.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "capability-list.h"
#include "capability-util.h"
#include "errno-list.h" #include "errno-list.h"
#include "extract-word.h" #include "extract-word.h"
#include "locale-util.h" #include "locale-util.h"
@ -809,3 +811,39 @@ bool nft_identifier_valid(const char *id) {
return in_charset(id + 1, ALPHANUMERICAL "/\\_."); return in_charset(id + 1, ALPHANUMERICAL "/\\_.");
} }
int parse_capability_set(const char *s, uint64_t initial, uint64_t *current) {
int r;
assert(s);
assert(current);
if (isempty(s)) {
*current = CAP_MASK_UNSET;
return 1;
}
bool invert = false;
if (s[0] == '~') {
invert = true;
s++;
}
uint64_t parsed;
r = capability_set_from_string(s, &parsed);
if (r < 0)
return r;
if (parsed == 0 || *current == initial)
/* "~" or uninitialized data -> replace */
*current = invert ? all_capabilities() & ~parsed : parsed;
else {
/* previous data -> merge */
if (invert)
*current &= ~parsed;
else
*current |= parsed;
}
return r;
}

View File

@ -22,6 +22,8 @@ int parse_errno(const char *t);
int parse_fd(const char *t); int parse_fd(const char *t);
int parse_user_shell(const char *s, char **ret_sh, bool *ret_copy); int parse_user_shell(const char *s, char **ret_sh, bool *ret_copy);
int parse_capability_set(const char *s, uint64_t initial, uint64_t *capability_set);
#define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30) #define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
#define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29) #define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)
#define SAFE_ATO_REFUSE_LEADING_WHITESPACE (1U << 28) #define SAFE_ATO_REFUSE_LEADING_WHITESPACE (1U << 28)

View File

@ -636,7 +636,7 @@ void exec_context_init(ExecContext *c) {
.timer_slack_nsec = NSEC_INFINITY, .timer_slack_nsec = NSEC_INFINITY,
.personality = PERSONALITY_INVALID, .personality = PERSONALITY_INVALID,
.timeout_clean_usec = USEC_INFINITY, .timeout_clean_usec = USEC_INFINITY,
.capability_bounding_set = CAP_MASK_UNSET, .capability_bounding_set = CAP_MASK_ALL,
.restrict_namespaces = NAMESPACE_FLAGS_INITIAL, .restrict_namespaces = NAMESPACE_FLAGS_INITIAL,
.delegate_namespaces = NAMESPACE_FLAGS_INITIAL, .delegate_namespaces = NAMESPACE_FLAGS_INITIAL,
.log_level_max = -1, .log_level_max = -1,

View File

@ -17,7 +17,6 @@
#include "bpf-restrict-fs.h" #include "bpf-restrict-fs.h"
#include "bus-error.h" #include "bus-error.h"
#include "calendarspec.h" #include "calendarspec.h"
#include "capability-list.h"
#include "capability-util.h" #include "capability-util.h"
#include "cgroup-setup.h" #include "cgroup-setup.h"
#include "condition.h" #include "condition.h"
@ -1873,41 +1872,22 @@ int config_parse_capability_set(
void *userdata) { void *userdata) {
uint64_t *capability_set = ASSERT_PTR(data); uint64_t *capability_set = ASSERT_PTR(data);
uint64_t sum = 0, initial, def;
bool invert = false;
int r; int r;
assert(filename); assert(filename);
assert(lvalue); assert(lvalue);
assert(rvalue); assert(rvalue);
if (rvalue[0] == '~') { uint64_t initial = streq(lvalue, "CapabilityBoundingSet") ? CAP_MASK_ALL : 0;
invert = true;
rvalue++;
}
if (streq(lvalue, "CapabilityBoundingSet")) { r = parse_capability_set(rvalue, initial, capability_set);
initial = CAP_MASK_ALL; /* initialized to all bits on */
def = CAP_MASK_UNSET; /* not set */
} else
def = initial = 0; /* All bits off */
r = capability_set_from_string(rvalue, &sum);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s= specifier '%s', ignoring: %m", lvalue, rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s= specifier '%s', ignoring: %m", lvalue, rvalue);
return 0; return 0;
} }
if (sum == 0 || *capability_set == def) if (*capability_set == CAP_MASK_UNSET)
/* "", "~" or uninitialized data -> replace */ *capability_set = 0;
*capability_set = invert ? ~sum : sum;
else {
/* previous data -> merge */
if (invert)
*capability_set &= ~sum;
else
*capability_set |= sum;
}
return 0; return 0;
} }

View File

@ -2768,7 +2768,7 @@ static void reset_arguments(void) {
arg_default_environment = strv_free(arg_default_environment); arg_default_environment = strv_free(arg_default_environment);
arg_manager_environment = strv_free(arg_manager_environment); arg_manager_environment = strv_free(arg_manager_environment);
arg_capability_bounding_set = CAP_MASK_UNSET; arg_capability_bounding_set = CAP_MASK_ALL;
arg_no_new_privs = false; arg_no_new_privs = false;
arg_protect_system = -1; arg_protect_system = -1;
arg_timer_slack_nsec = NSEC_INFINITY; arg_timer_slack_nsec = NSEC_INFINITY;

View File

@ -55,6 +55,13 @@ static inline int strcmp_ptr(const sd_char *a, const sd_char *b) {
return CMP(a, b); return CMP(a, b);
} }
static inline int strncmp_ptr(const sd_char *a, const sd_char *b, size_t n) {
if (a && b)
return strncmp(a, b, n);
return CMP(a, b);
}
static inline int strcasecmp_ptr(const sd_char *a, const sd_char *b) { static inline int strcasecmp_ptr(const sd_char *a, const sd_char *b) {
if (a && b) if (a && b)
return strcasecmp(a, b); return strcasecmp(a, b);
@ -66,6 +73,10 @@ static inline bool streq_ptr(const sd_char *a, const sd_char *b) {
return strcmp_ptr(a, b) == 0; return strcmp_ptr(a, b) == 0;
} }
static inline bool strneq_ptr(const sd_char *a, const sd_char *b, size_t n) {
return strncmp_ptr(a, b, n) == 0;
}
static inline bool strcaseeq_ptr(const sd_char *a, const sd_char *b) { static inline bool strcaseeq_ptr(const sd_char *a, const sd_char *b) {
return strcasecmp_ptr(a, b) == 0; return strcasecmp_ptr(a, b) == 0;
} }

View File

@ -107,8 +107,8 @@ static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
static bool arg_and_resize = false; static bool arg_and_resize = false;
static bool arg_and_change_password = false; static bool arg_and_change_password = false;
static ExportFormat arg_export_format = EXPORT_FORMAT_FULL; static ExportFormat arg_export_format = EXPORT_FORMAT_FULL;
static uint64_t arg_capability_bounding_set = UINT64_MAX; static uint64_t arg_capability_bounding_set = CAP_MASK_UNSET;
static uint64_t arg_capability_ambient_set = UINT64_MAX; static uint64_t arg_capability_ambient_set = CAP_MASK_UNSET;
static char *arg_blob_dir = NULL; static char *arg_blob_dir = NULL;
static bool arg_blob_clear = false; static bool arg_blob_clear = false;
static Hashmap *arg_blob_files = NULL; static Hashmap *arg_blob_files = NULL;
@ -4784,9 +4784,8 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CAPABILITY_AMBIENT_SET: case ARG_CAPABILITY_AMBIENT_SET:
case ARG_CAPABILITY_BOUNDING_SET: { case ARG_CAPABILITY_BOUNDING_SET: {
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
bool subtract = false; uint64_t *which;
uint64_t parsed, *which, updated; const char *field;
const char *p, *field;
if (c == ARG_CAPABILITY_AMBIENT_SET) { if (c == ARG_CAPABILITY_AMBIENT_SET) {
which = &arg_capability_ambient_set; which = &arg_capability_ambient_set;
@ -4797,42 +4796,27 @@ static int parse_argv(int argc, char *argv[]) {
field = "capabilityBoundingSet"; field = "capabilityBoundingSet";
} }
if (isempty(optarg)) { r = parse_capability_set(optarg, CAP_MASK_UNSET, which);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capabilities in capability string '%s'.", optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse capability string '%s': %m", optarg);
if (*which == CAP_MASK_UNSET) {
r = drop_from_identity(field); r = drop_from_identity(field);
if (r < 0) if (r < 0)
return r; return r;
*which = UINT64_MAX;
break; break;
} }
p = optarg; if (capability_set_to_strv(*which, &l) < 0)
if (*p == '~') {
subtract = true;
p++;
}
r = capability_set_from_string(p, &parsed);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capabilities in capability string '%s'.", p);
if (r < 0)
return log_error_errno(r, "Failed to parse capability string '%s': %m", p);
if (*which == UINT64_MAX)
updated = subtract ? all_capabilities() & ~parsed : parsed;
else if (subtract)
updated = *which & ~parsed;
else
updated = *which | parsed;
if (capability_set_to_strv(updated, &l) < 0)
return log_oom(); return log_oom();
r = sd_json_variant_set_field_strv(match_identity ?: &arg_identity_extra, field, l); r = sd_json_variant_set_field_strv(match_identity ?: &arg_identity_extra, field, l);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field); return log_error_errno(r, "Failed to set %s field: %m", field);
*which = updated;
break; break;
} }

View File

@ -1788,12 +1788,10 @@ static int luks_format(
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to generate volume key: %m"); return log_error_errno(r, "Failed to generate volume key: %m");
#if HAVE_CRYPT_SET_METADATA_SIZE
/* Increase the metadata space to 4M, the largest LUKS2 supports */ /* Increase the metadata space to 4M, the largest LUKS2 supports */
r = sym_crypt_set_metadata_size(cd, 4096U*1024U, 0); r = sym_crypt_set_metadata_size(cd, 4096U*1024U, 0);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to change LUKS2 metadata size: %m"); return log_error_errno(r, "Failed to change LUKS2 metadata size: %m");
#endif
build_good_pbkdf(&good_pbkdf, hr); build_good_pbkdf(&good_pbkdf, hr);
build_minimal_pbkdf(&minimal_pbkdf, hr); build_minimal_pbkdf(&minimal_pbkdf, hr);

View File

@ -31,6 +31,11 @@ int json_dispatch_unhex_iovec(const char *name, sd_json_variant *variant, sd_jso
size_t sz; size_t sz;
int r; int r;
if (sd_json_variant_is_null(variant)) {
iovec_done(iov);
return 0;
}
if (!sd_json_variant_is_string(variant)) if (!sd_json_variant_is_string(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name)); return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
@ -49,6 +54,11 @@ int json_dispatch_unbase64_iovec(const char *name, sd_json_variant *variant, sd_
size_t sz; size_t sz;
int r; int r;
if (sd_json_variant_is_null(variant)) {
iovec_done(iov);
return 0;
}
if (!sd_json_variant_is_string(variant)) if (!sd_json_variant_is_string(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name)); return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
@ -68,6 +78,11 @@ int json_dispatch_byte_array_iovec(const char *name, sd_json_variant *variant, s
assert(variant); assert(variant);
if (sd_json_variant_is_null(variant)) {
iovec_done(iov);
return 0;
}
if (!sd_json_variant_is_array(variant)) if (!sd_json_variant_is_array(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name)); return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
@ -169,6 +184,11 @@ int json_dispatch_in_addr(const char *name, sd_json_variant *variant, sd_json_di
_cleanup_(iovec_done) struct iovec iov = {}; _cleanup_(iovec_done) struct iovec iov = {};
int r; int r;
if (sd_json_variant_is_null(variant)) {
*address = (struct in_addr) {};
return 0;
}
r = json_dispatch_byte_array_iovec(name, variant, flags, &iov); r = json_dispatch_byte_array_iovec(name, variant, flags, &iov);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -5292,6 +5292,11 @@ _public_ int sd_json_dispatch_stdbool(const char *name, sd_json_variant *variant
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*b = false;
return 0;
}
if (!sd_json_variant_is_boolean(variant)) if (!sd_json_variant_is_boolean(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a boolean.", strna(name)); return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a boolean.", strna(name));
@ -5305,6 +5310,11 @@ _public_ int sd_json_dispatch_intbool(const char *name, sd_json_variant *variant
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*b = false;
return 0;
}
if (!sd_json_variant_is_boolean(variant)) if (!sd_json_variant_is_boolean(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a boolean.", strna(name)); return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a boolean.", strna(name));
@ -5336,6 +5346,11 @@ _public_ int sd_json_dispatch_int64(const char *name, sd_json_variant *variant,
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*i = -1;
return 0;
}
/* Also accept numbers formatted as string, to increase compatibility with less capable JSON /* Also accept numbers formatted as string, to increase compatibility with less capable JSON
* implementations that cannot do 64bit integers. */ * implementations that cannot do 64bit integers. */
if (sd_json_variant_is_string(variant) && safe_atoi64(sd_json_variant_string(variant), i) >= 0) if (sd_json_variant_is_string(variant) && safe_atoi64(sd_json_variant_string(variant), i) >= 0)
@ -5354,6 +5369,11 @@ _public_ int sd_json_dispatch_uint64(const char *name, sd_json_variant *variant,
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*u = UINT64_MAX;
return 0;
}
/* Since 64bit values (in particular unsigned ones) in JSON are problematic, let's also accept them /* Since 64bit values (in particular unsigned ones) in JSON are problematic, let's also accept them
* formatted as strings. If this is not desired make sure to set the .type field in * formatted as strings. If this is not desired make sure to set the .type field in
* sd_json_dispatch_field to SD_JSON_UNSIGNED rather than _SD_JSON_VARIANT_TYPE_INVALID, so that * sd_json_dispatch_field to SD_JSON_UNSIGNED rather than _SD_JSON_VARIANT_TYPE_INVALID, so that
@ -5377,6 +5397,11 @@ _public_ int sd_json_dispatch_uint32(const char *name, sd_json_variant *variant,
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*u = UINT32_MAX;
return 0;
}
r = sd_json_dispatch_uint64(name, variant, flags, &u64); r = sd_json_dispatch_uint64(name, variant, flags, &u64);
if (r < 0) if (r < 0)
return r; return r;
@ -5399,6 +5424,11 @@ _public_ int sd_json_dispatch_int32(const char *name, sd_json_variant *variant,
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*i = -1;
return 0;
}
r = sd_json_dispatch_int64(name, variant, flags, &i64); r = sd_json_dispatch_int64(name, variant, flags, &i64);
if (r < 0) if (r < 0)
return r; return r;
@ -5421,6 +5451,11 @@ _public_ int sd_json_dispatch_int16(const char *name, sd_json_variant *variant,
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*i = -1;
return 0;
}
r = sd_json_dispatch_int64(name, variant, flags, &i64); r = sd_json_dispatch_int64(name, variant, flags, &i64);
if (r < 0) if (r < 0)
return r; return r;
@ -5440,6 +5475,11 @@ _public_ int sd_json_dispatch_uint16(const char *name, sd_json_variant *variant,
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*u = UINT16_MAX;
return 0;
}
r = sd_json_dispatch_uint64(name, variant, flags, &u64); r = sd_json_dispatch_uint64(name, variant, flags, &u64);
if (r < 0) if (r < 0)
return r; return r;
@ -5459,6 +5499,11 @@ _public_ int sd_json_dispatch_int8(const char *name, sd_json_variant *variant, s
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*i = -1;
return 0;
}
r = sd_json_dispatch_int64(name, variant, flags, &i64); r = sd_json_dispatch_int64(name, variant, flags, &i64);
if (r < 0) if (r < 0)
return r; return r;
@ -5478,6 +5523,11 @@ _public_ int sd_json_dispatch_uint8(const char *name, sd_json_variant *variant,
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*u = UINT8_MAX;
return 0;
}
r = sd_json_dispatch_uint64(name, variant, flags, &u64); r = sd_json_dispatch_uint64(name, variant, flags, &u64);
if (r < 0) if (r < 0)
return r; return r;
@ -5495,6 +5545,11 @@ _public_ int sd_json_dispatch_double(const char *name, sd_json_variant *variant,
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*d = NAN;
return 0;
}
/* Note, this will take care of parsing NaN, -Infinity, Infinity for us */ /* Note, this will take care of parsing NaN, -Infinity, Infinity for us */
if (sd_json_variant_is_string(variant) && safe_atod(sd_json_variant_string(variant), d) >= 0) if (sd_json_variant_is_string(variant) && safe_atod(sd_json_variant_string(variant), d) >= 0)
return 0; return 0;
@ -5514,6 +5569,11 @@ _public_ int sd_json_dispatch_string(const char *name, sd_json_variant *variant,
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
if (sd_json_variant_is_null(variant)) {
*s = mfree(*s);
return 0;
}
r = sd_json_dispatch_const_string(name, variant, flags, &n); r = sd_json_dispatch_const_string(name, variant, flags, &n);
if (r < 0) if (r < 0)
return r; return r;
@ -5616,7 +5676,8 @@ _public_ int sd_json_dispatch_variant_noref(const char *name, sd_json_variant *v
_public_ int sd_json_dispatch_uid_gid(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) { _public_ int sd_json_dispatch_uid_gid(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
uid_t *uid = userdata; uid_t *uid = userdata;
uint64_t k; uint32_t k;
int r;
assert_return(variant, -EINVAL); assert_return(variant, -EINVAL);
assert_return(userdata, -EINVAL); assert_return(userdata, -EINVAL);
@ -5633,11 +5694,10 @@ _public_ int sd_json_dispatch_uid_gid(const char *name, sd_json_variant *variant
return 0; return 0;
} }
if (!sd_json_variant_is_unsigned(variant)) r = sd_json_dispatch_uint32(name, variant, flags, &k);
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name)); if (r < 0)
return r;
k = sd_json_variant_unsigned(variant); if (!uid_is_valid(k))
if (k > UINT32_MAX || !uid_is_valid(k))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid UID/GID.", strna(name)); return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid UID/GID.", strna(name));
*uid = k; *uid = k;
@ -5678,12 +5738,18 @@ _public_ int sd_json_dispatch_signal(const char *name, sd_json_variant *variant,
} }
int k; int k;
r = sd_json_dispatch_int(name, variant, flags, &k); if (sd_json_variant_is_string(variant)) {
if (r < 0) k = signal_from_string(sd_json_variant_string(variant));
return r; if (k < 0)
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid signal.", strna(name));
} else {
r = sd_json_dispatch_int(name, variant, flags, &k);
if (r < 0)
return r;
if (!SIGNAL_VALID(k)) if (!SIGNAL_VALID(k))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid signal.", strna(name)); return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid signal.", strna(name));
}
*signo = k; *signo = k;
return 0; return 0;

View File

@ -2421,6 +2421,15 @@ _public_ int sd_varlink_collect_full(
if (sd_json_variant_elements(collected) >= VARLINK_COLLECT_MAX) if (sd_json_variant_elements(collected) >= VARLINK_COLLECT_MAX)
return varlink_log_errno(v, SYNTHETIC_ERRNO(E2BIG), "Number of reply messages grew too large (%zu) while collecting.", sd_json_variant_elements(collected)); return varlink_log_errno(v, SYNTHETIC_ERRNO(E2BIG), "Number of reply messages grew too large (%zu) while collecting.", sd_json_variant_elements(collected));
_cleanup_(sd_json_variant_unrefp) sd_json_variant *empty = NULL;
if (!p) {
r = sd_json_variant_new_array(&empty, /* array= */ NULL, /* n= */ 0);
if (r < 0)
return r;
p = empty;
}
r = sd_json_variant_append_array(&collected, p); r = sd_json_variant_append_array(&collected, p);
if (r < 0) if (r < 0)
return varlink_log_errno(v, r, "Failed to append JSON object to array: %m"); return varlink_log_errno(v, r, "Failed to append JSON object to array: %m");

View File

@ -96,7 +96,7 @@ static int parse_caps(
if (!caps) if (!caps)
continue; continue;
if (*caps == UINT64_MAX) if (*caps == CAP_MASK_UNSET)
b = subtract ? all_capabilities() : 0; b = subtract ? all_capabilities() : 0;
else else
b = *caps; b = *caps;
@ -764,14 +764,14 @@ static int apply_user_record_settings(
uint64_t a, b; uint64_t a, b;
a = user_record_capability_ambient_set(ur); a = user_record_capability_ambient_set(ur);
if (a == UINT64_MAX) if (a == CAP_MASK_UNSET)
a = default_capability_ambient_set; a = default_capability_ambient_set;
b = user_record_capability_bounding_set(ur); b = user_record_capability_bounding_set(ur);
if (b == UINT64_MAX) if (b == CAP_MASK_UNSET)
b = default_capability_bounding_set; b = default_capability_bounding_set;
if (a != UINT64_MAX && a != 0) { if (a != CAP_MASK_UNSET && a != 0) {
a &= b; a &= b;
r = capability_ambient_set_apply(a, /* also_inherit= */ true); r = capability_ambient_set_apply(a, /* also_inherit= */ true);
@ -780,7 +780,7 @@ static int apply_user_record_settings(
"Failed to set ambient capabilities, ignoring: %m"); "Failed to set ambient capabilities, ignoring: %m");
} }
if (b != UINT64_MAX && !cap_test_all(b)) { if (b != CAP_MASK_UNSET && !cap_test_all(b)) {
r = capability_bounding_set_drop(b, /* right_now= */ false); r = capability_bounding_set_drop(b, /* right_now= */ false);
if (r < 0) if (r < 0)
pam_syslog_errno(handle, LOG_ERR, r, pam_syslog_errno(handle, LOG_ERR, r,
@ -802,7 +802,7 @@ static uint64_t pick_default_capability_ambient_set(
return ur && return ur &&
user_record_disposition(ur) == USER_REGULAR && user_record_disposition(ur) == USER_REGULAR &&
(streq_ptr(service, "systemd-user") || !isempty(seat)) ? (UINT64_C(1) << CAP_WAKE_ALARM) : UINT64_MAX; (streq_ptr(service, "systemd-user") || !isempty(seat)) ? (UINT64_C(1) << CAP_WAKE_ALARM) : CAP_MASK_UNSET;
} }
typedef struct SessionContext { typedef struct SessionContext {
@ -1735,7 +1735,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
pam_log_setup(); pam_log_setup();
uint64_t default_capability_bounding_set = UINT64_MAX, default_capability_ambient_set = UINT64_MAX; uint64_t default_capability_bounding_set = CAP_MASK_UNSET, default_capability_ambient_set = CAP_MASK_UNSET;
const char *class_pam = NULL, *type_pam = NULL, *desktop_pam = NULL, *area_pam = NULL; const char *class_pam = NULL, *type_pam = NULL, *desktop_pam = NULL, *area_pam = NULL;
bool debug = false; bool debug = false;
if (parse_argv(handle, if (parse_argv(handle,
@ -1800,7 +1800,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
if (r != PAM_SUCCESS) if (r != PAM_SUCCESS)
return r; return r;
if (default_capability_ambient_set == UINT64_MAX) if (default_capability_ambient_set == CAP_MASK_UNSET)
default_capability_ambient_set = pick_default_capability_ambient_set(ur, c.service, c.seat); default_capability_ambient_set = pick_default_capability_ambient_set(ur, c.service, c.seat);
r = apply_user_record_settings(handle, ur, debug, default_capability_bounding_set, default_capability_ambient_set); r = apply_user_record_settings(handle, ur, debug, default_capability_bounding_set, default_capability_ambient_set);

View File

@ -324,7 +324,7 @@ static int oci_capabilities(const char *name, sd_json_variant *v, sd_json_dispat
if (r < 0) if (r < 0)
return r; return r;
if (s->full_capabilities.bounding != UINT64_MAX) { if (s->full_capabilities.bounding != CAP_MASK_UNSET) {
s->capability = s->full_capabilities.bounding; s->capability = s->full_capabilities.bounding;
s->drop_capability = ~s->full_capabilities.bounding; s->drop_capability = ~s->full_capabilities.bounding;
} }

View File

@ -1694,7 +1694,7 @@ static int verify_arguments(void) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --port= without private networking."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --port= without private networking.");
if (arg_caps_ambient) { if (arg_caps_ambient) {
if (arg_caps_ambient == UINT64_MAX) if (arg_caps_ambient == CAP_MASK_UNSET)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "AmbientCapability= does not support the value all."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "AmbientCapability= does not support the value all.");
if ((arg_caps_ambient & arg_caps_retain) != arg_caps_ambient) if ((arg_caps_ambient & arg_caps_retain) != arg_caps_ambient)

File diff suppressed because it is too large Load Diff

View File

@ -1015,14 +1015,12 @@ static int verb_service(int argc, char **argv, void *userdata) {
} }
static int resolve_openpgp(sd_bus *bus, const char *address) { static int resolve_openpgp(sd_bus *bus, const char *address) {
const char *domain, *full;
int r; int r;
_cleanup_free_ char *hashed = NULL;
assert(bus); assert(bus);
assert(address); assert(address);
domain = strrchr(address, '@'); const char *domain = strrchr(address, '@');
if (!domain) if (!domain)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Address does not contain '@': \"%s\"", address); "Address does not contain '@': \"%s\"", address);
@ -1031,34 +1029,50 @@ static int resolve_openpgp(sd_bus *bus, const char *address) {
"Address starts or ends with '@': \"%s\"", address); "Address starts or ends with '@': \"%s\"", address);
domain++; domain++;
_cleanup_free_ char *hashed = NULL;
r = string_hashsum_sha256(address, domain - 1 - address, &hashed); r = string_hashsum_sha256(address, domain - 1 - address, &hashed);
if (r < 0) if (r < 0)
return log_error_errno(r, "Hashing failed: %m"); return log_error_errno(r, "Hashing failed: %m");
strshorten(hashed, 56); strshorten(hashed, 56);
full = strjoina(hashed, "._openpgpkey.", domain); _cleanup_free_ char *suffix = NULL;
r = dns_name_concat("_openpgpkey", domain, /* flags= */ 0, &suffix);
if (r < 0)
return log_error_errno(r, "Failed to join DNS suffix: %m");
_cleanup_free_ char *full = NULL;
r = dns_name_concat(hashed, suffix, /* flags= */ 0, &full);
if (r < 0)
return log_error_errno(r, "Failed to join OPENPGPKEY name: %m");
log_debug("Looking up \"%s\".", full); log_debug("Looking up \"%s\".", full);
r = resolve_record(bus, full, r = resolve_record(
arg_class ?: DNS_CLASS_IN, bus,
arg_type ?: DNS_TYPE_OPENPGPKEY, false); full,
arg_class ?: DNS_CLASS_IN,
arg_type ?: DNS_TYPE_OPENPGPKEY,
/* warn_missing= */ false);
if (!IN_SET(r, -ENXIO, -ESRCH)) /* Not NXDOMAIN or NODATA? Then fail immedately. */
return r;
if (IN_SET(r, -ENXIO, -ESRCH)) { /* NXDOMAIN or NODATA? */ hashed = mfree(hashed);
hashed = mfree(hashed); r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
r = string_hashsum_sha224(address, domain - 1 - address, &hashed); if (r < 0)
if (r < 0) return log_error_errno(r, "Hashing failed: %m");
return log_error_errno(r, "Hashing failed: %m");
full = strjoina(hashed, "._openpgpkey.", domain); full = mfree(full);
log_debug("Looking up \"%s\".", full); r = dns_name_concat(hashed, suffix, /* flags= */ 0, &full);
if (r < 0)
return log_error_errno(r, "Failed to join OPENPGPKEY name: %m");
log_debug("Looking up \"%s\".", full);
return resolve_record(bus, full, return resolve_record(
arg_class ?: DNS_CLASS_IN, bus,
arg_type ?: DNS_TYPE_OPENPGPKEY, true); full,
} arg_class ?: DNS_CLASS_IN,
arg_type ?: DNS_TYPE_OPENPGPKEY,
return r; /* warn_missing= */ true);
} }
static int verb_openpgp(int argc, char **argv, void *userdata) { static int verb_openpgp(int argc, char **argv, void *userdata) {

View File

@ -8,6 +8,8 @@
#include "blockdev-util.h" #include "blockdev-util.h"
#include "device-private.h" #include "device-private.h"
#include "device-util.h" #include "device-util.h"
#include "errno-util.h"
#include "string-util.h"
#include "strv.h" #include "strv.h"
#include "terminal-util.h" #include "terminal-util.h"
@ -16,6 +18,9 @@ void block_device_done(BlockDevice *d) {
d->node = mfree(d->node); d->node = mfree(d->node);
d->symlinks = strv_free(d->symlinks); d->symlinks = strv_free(d->symlinks);
d->model = mfree(d->model);
d->vendor = mfree(d->vendor);
d->subsystem = mfree(d->subsystem);
} }
void block_device_array_free(BlockDevice *d, size_t n_devices) { void block_device_array_free(BlockDevice *d, size_t n_devices) {
@ -26,6 +31,61 @@ void block_device_array_free(BlockDevice *d, size_t n_devices) {
free(d); free(d);
} }
static int blockdev_get_prop(sd_device *d, const char *prop1, const char *prop2, char **ret_value) {
int r, ret = 0;
assert(d);
assert(prop1);
assert(ret_value);
FOREACH_STRING(prop, prop1, prop2) {
const char *m = NULL;
r = sd_device_get_property_value(d, prop, &m);
if (r < 0 && r != -ENOENT)
RET_GATHER(ret, log_device_debug_errno(d, r, "Failed to acquire '%s' from device, ignoring: %m", prop));
else if (!isempty(m))
return strdup_to(ret_value, m);
}
return ret < 0 ? ret : -ENOENT;
}
static int blockdev_get_subsystem(sd_device *d, char **ret_subsystem) {
int r;
assert(d);
assert(ret_subsystem);
/* We prefer the explicitly set block device subsystem property, because if it is set it's generally
* the most useful. If it's not set we'll look for the subsystem of the first parent device that
* isn't of subsystem 'block'. The former covers 'virtual' block devices such as loopback, device
* mapper, zram, while the latter covers physical block devices such as USB or NVME. */
r = blockdev_get_prop(d, "ID_BLOCK_SUBSYSTEM", /* prop2= */ NULL, ret_subsystem);
if (r >= 0)
return r;
int ret = r != -ENOENT ? r : 0;
sd_device *q = d;
for (;;) {
r = sd_device_get_parent(q, &q);
if (r < 0) {
if (r != -ENOENT)
RET_GATHER(ret, log_device_debug_errno(q, r, "Failed to get parent device, ignoring: %m"));
break;
}
const char *s = NULL;
r = sd_device_get_subsystem(q, &s);
if (r < 0)
RET_GATHER(ret, log_device_debug_errno(q, r, "Failed to get subsystem of device, ignoring: %m"));
else if (!isempty(s) && !streq(s, "block"))
return strdup_to(ret_subsystem, s);
}
return ret < 0 ? ret : -ENOENT;
}
int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *ret_n_devices) { int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *ret_n_devices) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
int r; int r;
@ -65,7 +125,7 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
r = sd_device_get_devname(dev, &node); r = sd_device_get_devname(dev, &node);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "Failed to get device node of discovered block device, ignoring: %m"); log_device_warning_errno(dev, r, "Failed to get device node of discovered block device, ignoring: %m");
continue; continue;
} }
@ -74,7 +134,7 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
r = sd_device_get_devnum(dev, &devno); r = sd_device_get_devnum(dev, &devno);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "Failed to get major/minor of discovered block device, ignoring: %m"); log_device_warning_errno(dev, r, "Failed to get major/minor of discovered block device, ignoring: %m");
continue; continue;
} }
@ -85,7 +145,7 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
if (FLAGS_SET(flags, BLOCKDEV_LIST_IGNORE_ZRAM)) { if (FLAGS_SET(flags, BLOCKDEV_LIST_IGNORE_ZRAM)) {
r = device_sysname_startswith(dev, "zram"); r = device_sysname_startswith(dev, "zram");
if (r < 0) { if (r < 0) {
log_warning_errno(r, "Failed to check device name of discovered block device '%s', ignoring: %m", node); log_device_warning_errno(dev, r, "Failed to check device name of discovered block device '%s', ignoring: %m", node);
continue; continue;
} }
if (r > 0) if (r > 0)
@ -95,27 +155,26 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
if (FLAGS_SET(flags, BLOCKDEV_LIST_REQUIRE_PARTITION_SCANNING)) { if (FLAGS_SET(flags, BLOCKDEV_LIST_REQUIRE_PARTITION_SCANNING)) {
r = blockdev_partscan_enabled(dev); r = blockdev_partscan_enabled(dev);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "Unable to determine whether '%s' supports partition scanning, skipping device: %m", node); log_device_warning_errno(dev, r, "Unable to determine whether '%s' supports partition scanning, skipping device: %m", node);
continue; continue;
} }
if (r == 0) { if (r == 0) {
log_debug("Device '%s' does not support partition scanning, skipping.", node); log_device_debug(dev, "Device '%s' does not support partition scanning, skipping.", node);
continue; continue;
} }
} }
uint64_t size = UINT64_MAX; uint64_t size = UINT64_MAX;
if (FLAGS_SET(flags, BLOCKDEV_LIST_IGNORE_EMPTY) || ret_devices) { if (FLAGS_SET(flags, BLOCKDEV_LIST_IGNORE_EMPTY) || ret_devices) {
r = device_get_sysattr_u64(dev, "size", &size); r = device_get_sysattr_u64(dev, "size", &size);
if (r < 0) if (r < 0)
log_debug_errno(r, "Failed to acquire size of device '%s', ignoring: %m", node); log_device_debug_errno(dev, r, "Failed to acquire size of device '%s', ignoring: %m", node);
else else
/* the 'size' sysattr is always in multiples of 512, even on 4K sector block devices! */ /* the 'size' sysattr is always in multiples of 512, even on 4K sector block devices! */
assert_se(MUL_ASSIGN_SAFE(&size, 512)); /* Overflow check for coverity */ assert_se(MUL_ASSIGN_SAFE(&size, 512)); /* Overflow check for coverity */
if (size == 0 && FLAGS_SET(flags, BLOCKDEV_LIST_IGNORE_EMPTY)) { if (size == 0 && FLAGS_SET(flags, BLOCKDEV_LIST_IGNORE_EMPTY)) {
log_debug("Device '%s' has a zero size, assuming drive without a medium, skipping.", node); log_device_debug(dev, "Device '%s' has a zero size, assuming drive without a medium, skipping.", node);
continue; continue;
} }
} }
@ -129,11 +188,18 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
strv_sort(list); strv_sort(list);
} }
_cleanup_free_ char *model = NULL, *vendor = NULL, *subsystem = NULL;
if (FLAGS_SET(flags, BLOCKDEV_LIST_METADATA)) {
(void) blockdev_get_prop(dev, "ID_MODEL_FROM_DATABASE", "ID_MODEL", &model);
(void) blockdev_get_prop(dev, "ID_VENDOR_FROM_DATABASE", "ID_VENDOR", &vendor);
(void) blockdev_get_subsystem(dev, &subsystem);
}
if (ret_devices) { if (ret_devices) {
uint64_t diskseq = UINT64_MAX; uint64_t diskseq = UINT64_MAX;
r = sd_device_get_diskseq(dev, &diskseq); r = sd_device_get_diskseq(dev, &diskseq);
if (r < 0) if (r < 0)
log_debug_errno(r, "Failed to acquire diskseq of device '%s', ignoring: %m", node); log_device_debug_errno(dev, r, "Failed to acquire diskseq of device '%s', ignoring: %m", node);
if (!GREEDY_REALLOC(l, n+1)) if (!GREEDY_REALLOC(l, n+1))
return log_oom(); return log_oom();
@ -147,6 +213,9 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
.symlinks = TAKE_PTR(list), .symlinks = TAKE_PTR(list),
.diskseq = diskseq, .diskseq = diskseq,
.size = size, .size = size,
.model = TAKE_PTR(model),
.vendor = TAKE_PTR(vendor),
.subsystem = TAKE_PTR(subsystem),
}; };
} else { } else {

View File

@ -10,11 +10,15 @@ typedef enum BlockDevListFlags {
BLOCKDEV_LIST_REQUIRE_LUKS = 1 << 3, /* Only consider block devices with LUKS superblocks */ BLOCKDEV_LIST_REQUIRE_LUKS = 1 << 3, /* Only consider block devices with LUKS superblocks */
BLOCKDEV_LIST_IGNORE_ROOT = 1 << 4, /* Ignore the block device we are currently booted from */ BLOCKDEV_LIST_IGNORE_ROOT = 1 << 4, /* Ignore the block device we are currently booted from */
BLOCKDEV_LIST_IGNORE_EMPTY = 1 << 5, /* Ignore disks of zero size (usually drives without a medium) */ BLOCKDEV_LIST_IGNORE_EMPTY = 1 << 5, /* Ignore disks of zero size (usually drives without a medium) */
BLOCKDEV_LIST_METADATA = 1 << 6, /* Fill in model, vendor, subsystem */
} BlockDevListFlags; } BlockDevListFlags;
typedef struct BlockDevice { typedef struct BlockDevice {
char *node; char *node;
char **symlinks; char **symlinks;
char *model;
char *vendor;
char *subsystem;
uint64_t diskseq; uint64_t diskseq;
uint64_t size; /* in bytes */ uint64_t size; /* in bytes */
} BlockDevice; } BlockDevice;

View File

@ -16,9 +16,7 @@
static void *cryptsetup_dl = NULL; static void *cryptsetup_dl = NULL;
DLSYM_PROTOTYPE(crypt_activate_by_passphrase) = NULL; DLSYM_PROTOTYPE(crypt_activate_by_passphrase) = NULL;
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
DLSYM_PROTOTYPE(crypt_activate_by_signed_key) = NULL; DLSYM_PROTOTYPE(crypt_activate_by_signed_key) = NULL;
#endif
DLSYM_PROTOTYPE(crypt_activate_by_volume_key) = NULL; DLSYM_PROTOTYPE(crypt_activate_by_volume_key) = NULL;
DLSYM_PROTOTYPE(crypt_deactivate_by_name) = NULL; DLSYM_PROTOTYPE(crypt_deactivate_by_name) = NULL;
DLSYM_PROTOTYPE(crypt_format) = NULL; DLSYM_PROTOTYPE(crypt_format) = NULL;
@ -32,22 +30,27 @@ DLSYM_PROTOTYPE(crypt_get_type) = NULL;
DLSYM_PROTOTYPE(crypt_get_uuid) = NULL; DLSYM_PROTOTYPE(crypt_get_uuid) = NULL;
DLSYM_PROTOTYPE(crypt_get_verity_info) = NULL; DLSYM_PROTOTYPE(crypt_get_verity_info) = NULL;
DLSYM_PROTOTYPE(crypt_get_volume_key_size) = NULL; DLSYM_PROTOTYPE(crypt_get_volume_key_size) = NULL;
DLSYM_PROTOTYPE(crypt_header_restore) = NULL;
DLSYM_PROTOTYPE(crypt_init) = NULL; DLSYM_PROTOTYPE(crypt_init) = NULL;
DLSYM_PROTOTYPE(crypt_init_by_name) = NULL; DLSYM_PROTOTYPE(crypt_init_by_name) = NULL;
DLSYM_PROTOTYPE(crypt_keyslot_add_by_volume_key) = NULL; DLSYM_PROTOTYPE(crypt_keyslot_add_by_volume_key) = NULL;
DLSYM_PROTOTYPE(crypt_keyslot_destroy) = NULL; DLSYM_PROTOTYPE(crypt_keyslot_destroy) = NULL;
DLSYM_PROTOTYPE(crypt_keyslot_max) = NULL; DLSYM_PROTOTYPE(crypt_keyslot_max) = NULL;
DLSYM_PROTOTYPE(crypt_load) = NULL; DLSYM_PROTOTYPE(crypt_load) = NULL;
DLSYM_PROTOTYPE(crypt_resize) = NULL; DLSYM_PROTOTYPE(crypt_metadata_locking) = NULL;
#if HAVE_CRYPT_RESUME_BY_VOLUME_KEY DLSYM_PROTOTYPE(crypt_reencrypt_init_by_passphrase) = NULL;
DLSYM_PROTOTYPE(crypt_resume_by_volume_key) = NULL; #if HAVE_CRYPT_REENCRYPT_RUN
DLSYM_PROTOTYPE(crypt_reencrypt_run);
#else
DLSYM_PROTOTYPE(crypt_reencrypt);
#endif #endif
DLSYM_PROTOTYPE(crypt_resize) = NULL;
DLSYM_PROTOTYPE(crypt_resume_by_volume_key) = NULL;
DLSYM_PROTOTYPE(crypt_set_data_device) = NULL; DLSYM_PROTOTYPE(crypt_set_data_device) = NULL;
DLSYM_PROTOTYPE(crypt_set_data_offset) = NULL;
DLSYM_PROTOTYPE(crypt_set_debug_level) = NULL; DLSYM_PROTOTYPE(crypt_set_debug_level) = NULL;
DLSYM_PROTOTYPE(crypt_set_log_callback) = NULL; DLSYM_PROTOTYPE(crypt_set_log_callback) = NULL;
#if HAVE_CRYPT_SET_METADATA_SIZE
DLSYM_PROTOTYPE(crypt_set_metadata_size) = NULL; DLSYM_PROTOTYPE(crypt_set_metadata_size) = NULL;
#endif
DLSYM_PROTOTYPE(crypt_set_pbkdf_type) = NULL; DLSYM_PROTOTYPE(crypt_set_pbkdf_type) = NULL;
DLSYM_PROTOTYPE(crypt_suspend) = NULL; DLSYM_PROTOTYPE(crypt_suspend) = NULL;
DLSYM_PROTOTYPE(crypt_token_json_get) = NULL; DLSYM_PROTOTYPE(crypt_token_json_get) = NULL;
@ -66,19 +69,6 @@ DLSYM_PROTOTYPE(crypt_token_set_external_path) = NULL;
#endif #endif
DLSYM_PROTOTYPE(crypt_token_status) = NULL; DLSYM_PROTOTYPE(crypt_token_status) = NULL;
DLSYM_PROTOTYPE(crypt_volume_key_get) = NULL; DLSYM_PROTOTYPE(crypt_volume_key_get) = NULL;
#if HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE
DLSYM_PROTOTYPE(crypt_reencrypt_init_by_passphrase) = NULL;
#endif
#if HAVE_CRYPT_REENCRYPT_RUN
DLSYM_PROTOTYPE(crypt_reencrypt_run);
#elif HAVE_CRYPT_REENCRYPT
DLSYM_PROTOTYPE(crypt_reencrypt);
#endif
DLSYM_PROTOTYPE(crypt_metadata_locking) = NULL;
#if HAVE_CRYPT_SET_DATA_OFFSET
DLSYM_PROTOTYPE(crypt_set_data_offset) = NULL;
#endif
DLSYM_PROTOTYPE(crypt_header_restore) = NULL;
DLSYM_PROTOTYPE(crypt_volume_key_keyring) = NULL; DLSYM_PROTOTYPE(crypt_volume_key_keyring) = NULL;
static void cryptsetup_log_glue(int level, const char *msg, void *usrptr) { static void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
@ -237,9 +227,7 @@ int dlopen_cryptsetup(void) {
r = dlopen_many_sym_or_warn( r = dlopen_many_sym_or_warn(
&cryptsetup_dl, "libcryptsetup.so.12", LOG_DEBUG, &cryptsetup_dl, "libcryptsetup.so.12", LOG_DEBUG,
DLSYM_ARG(crypt_activate_by_passphrase), DLSYM_ARG(crypt_activate_by_passphrase),
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
DLSYM_ARG(crypt_activate_by_signed_key), DLSYM_ARG(crypt_activate_by_signed_key),
#endif
DLSYM_ARG(crypt_activate_by_volume_key), DLSYM_ARG(crypt_activate_by_volume_key),
DLSYM_ARG(crypt_deactivate_by_name), DLSYM_ARG(crypt_deactivate_by_name),
DLSYM_ARG(crypt_format), DLSYM_ARG(crypt_format),
@ -253,22 +241,27 @@ int dlopen_cryptsetup(void) {
DLSYM_ARG(crypt_get_uuid), DLSYM_ARG(crypt_get_uuid),
DLSYM_ARG(crypt_get_verity_info), DLSYM_ARG(crypt_get_verity_info),
DLSYM_ARG(crypt_get_volume_key_size), DLSYM_ARG(crypt_get_volume_key_size),
DLSYM_ARG(crypt_header_restore),
DLSYM_ARG(crypt_init), DLSYM_ARG(crypt_init),
DLSYM_ARG(crypt_init_by_name), DLSYM_ARG(crypt_init_by_name),
DLSYM_ARG(crypt_keyslot_add_by_volume_key), DLSYM_ARG(crypt_keyslot_add_by_volume_key),
DLSYM_ARG(crypt_keyslot_destroy), DLSYM_ARG(crypt_keyslot_destroy),
DLSYM_ARG(crypt_keyslot_max), DLSYM_ARG(crypt_keyslot_max),
DLSYM_ARG(crypt_load), DLSYM_ARG(crypt_load),
DLSYM_ARG(crypt_resize), DLSYM_ARG(crypt_metadata_locking),
#if HAVE_CRYPT_RESUME_BY_VOLUME_KEY DLSYM_ARG(crypt_reencrypt_init_by_passphrase),
DLSYM_ARG(crypt_resume_by_volume_key), #if HAVE_CRYPT_REENCRYPT_RUN
DLSYM_ARG(crypt_reencrypt_run),
#else
DLSYM_ARG(crypt_reencrypt),
#endif #endif
DLSYM_ARG(crypt_resize),
DLSYM_ARG(crypt_resume_by_volume_key),
DLSYM_ARG(crypt_set_data_device), DLSYM_ARG(crypt_set_data_device),
DLSYM_ARG(crypt_set_data_offset),
DLSYM_ARG(crypt_set_debug_level), DLSYM_ARG(crypt_set_debug_level),
DLSYM_ARG(crypt_set_log_callback), DLSYM_ARG(crypt_set_log_callback),
#if HAVE_CRYPT_SET_METADATA_SIZE
DLSYM_ARG(crypt_set_metadata_size), DLSYM_ARG(crypt_set_metadata_size),
#endif
DLSYM_ARG(crypt_set_pbkdf_type), DLSYM_ARG(crypt_set_pbkdf_type),
DLSYM_ARG(crypt_suspend), DLSYM_ARG(crypt_suspend),
DLSYM_ARG(crypt_token_json_get), DLSYM_ARG(crypt_token_json_get),
@ -281,19 +274,6 @@ int dlopen_cryptsetup(void) {
#endif #endif
DLSYM_ARG(crypt_token_status), DLSYM_ARG(crypt_token_status),
DLSYM_ARG(crypt_volume_key_get), DLSYM_ARG(crypt_volume_key_get),
#if HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE
DLSYM_ARG(crypt_reencrypt_init_by_passphrase),
#endif
#if HAVE_CRYPT_REENCRYPT_RUN
DLSYM_ARG(crypt_reencrypt_run),
#elif HAVE_CRYPT_REENCRYPT
DLSYM_ARG(crypt_reencrypt),
#endif
DLSYM_ARG(crypt_metadata_locking),
#if HAVE_CRYPT_SET_DATA_OFFSET
DLSYM_ARG(crypt_set_data_offset),
#endif
DLSYM_ARG(crypt_header_restore),
DLSYM_ARG(crypt_volume_key_keyring)); DLSYM_ARG(crypt_volume_key_keyring));
if (r <= 0) if (r <= 0)
return r; return r;

View File

@ -16,9 +16,7 @@
#endif #endif
extern DLSYM_PROTOTYPE(crypt_activate_by_passphrase); extern DLSYM_PROTOTYPE(crypt_activate_by_passphrase);
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
extern DLSYM_PROTOTYPE(crypt_activate_by_signed_key); extern DLSYM_PROTOTYPE(crypt_activate_by_signed_key);
#endif
extern DLSYM_PROTOTYPE(crypt_activate_by_volume_key); extern DLSYM_PROTOTYPE(crypt_activate_by_volume_key);
extern DLSYM_PROTOTYPE(crypt_deactivate_by_name); extern DLSYM_PROTOTYPE(crypt_deactivate_by_name);
extern DLSYM_PROTOTYPE(crypt_format); extern DLSYM_PROTOTYPE(crypt_format);
@ -32,22 +30,27 @@ extern DLSYM_PROTOTYPE(crypt_get_type);
extern DLSYM_PROTOTYPE(crypt_get_uuid); extern DLSYM_PROTOTYPE(crypt_get_uuid);
extern DLSYM_PROTOTYPE(crypt_get_verity_info); extern DLSYM_PROTOTYPE(crypt_get_verity_info);
extern DLSYM_PROTOTYPE(crypt_get_volume_key_size); extern DLSYM_PROTOTYPE(crypt_get_volume_key_size);
extern DLSYM_PROTOTYPE(crypt_header_restore);
extern DLSYM_PROTOTYPE(crypt_init); extern DLSYM_PROTOTYPE(crypt_init);
extern DLSYM_PROTOTYPE(crypt_init_by_name); extern DLSYM_PROTOTYPE(crypt_init_by_name);
extern DLSYM_PROTOTYPE(crypt_keyslot_add_by_volume_key); extern DLSYM_PROTOTYPE(crypt_keyslot_add_by_volume_key);
extern DLSYM_PROTOTYPE(crypt_keyslot_destroy); extern DLSYM_PROTOTYPE(crypt_keyslot_destroy);
extern DLSYM_PROTOTYPE(crypt_keyslot_max); extern DLSYM_PROTOTYPE(crypt_keyslot_max);
extern DLSYM_PROTOTYPE(crypt_load); extern DLSYM_PROTOTYPE(crypt_load);
extern DLSYM_PROTOTYPE(crypt_resize); extern DLSYM_PROTOTYPE(crypt_metadata_locking);
#if HAVE_CRYPT_RESUME_BY_VOLUME_KEY extern DLSYM_PROTOTYPE(crypt_reencrypt_init_by_passphrase);
extern DLSYM_PROTOTYPE(crypt_resume_by_volume_key); #if HAVE_CRYPT_REENCRYPT_RUN
extern DLSYM_PROTOTYPE(crypt_reencrypt_run);
#else
extern DLSYM_PROTOTYPE(crypt_reencrypt);
#endif #endif
extern DLSYM_PROTOTYPE(crypt_resize);
extern DLSYM_PROTOTYPE(crypt_resume_by_volume_key);
extern DLSYM_PROTOTYPE(crypt_set_data_device); extern DLSYM_PROTOTYPE(crypt_set_data_device);
extern DLSYM_PROTOTYPE(crypt_set_data_offset);
extern DLSYM_PROTOTYPE(crypt_set_debug_level); extern DLSYM_PROTOTYPE(crypt_set_debug_level);
extern DLSYM_PROTOTYPE(crypt_set_log_callback); extern DLSYM_PROTOTYPE(crypt_set_log_callback);
#if HAVE_CRYPT_SET_METADATA_SIZE
extern DLSYM_PROTOTYPE(crypt_set_metadata_size); extern DLSYM_PROTOTYPE(crypt_set_metadata_size);
#endif
extern DLSYM_PROTOTYPE(crypt_set_pbkdf_type); extern DLSYM_PROTOTYPE(crypt_set_pbkdf_type);
extern DLSYM_PROTOTYPE(crypt_suspend); extern DLSYM_PROTOTYPE(crypt_suspend);
extern DLSYM_PROTOTYPE(crypt_token_json_get); extern DLSYM_PROTOTYPE(crypt_token_json_get);
@ -64,19 +67,6 @@ extern DLSYM_PROTOTYPE(crypt_token_set_external_path);
#endif #endif
extern DLSYM_PROTOTYPE(crypt_token_status); extern DLSYM_PROTOTYPE(crypt_token_status);
extern DLSYM_PROTOTYPE(crypt_volume_key_get); extern DLSYM_PROTOTYPE(crypt_volume_key_get);
#if HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE
extern DLSYM_PROTOTYPE(crypt_reencrypt_init_by_passphrase);
#endif
#if HAVE_CRYPT_REENCRYPT_RUN
extern DLSYM_PROTOTYPE(crypt_reencrypt_run);
#elif HAVE_CRYPT_REENCRYPT
extern DLSYM_PROTOTYPE(crypt_reencrypt);
#endif
extern DLSYM_PROTOTYPE(crypt_metadata_locking);
#if HAVE_CRYPT_SET_DATA_OFFSET
extern DLSYM_PROTOTYPE(crypt_set_data_offset);
#endif
extern DLSYM_PROTOTYPE(crypt_header_restore);
extern DLSYM_PROTOTYPE(crypt_volume_key_keyring); extern DLSYM_PROTOTYPE(crypt_volume_key_keyring);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct crypt_device *, crypt_free, NULL); DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct crypt_device *, crypt_free, NULL);
@ -92,15 +82,6 @@ int cryptsetup_set_minimal_pbkdf(struct crypt_device *cd);
int cryptsetup_get_token_as_json(struct crypt_device *cd, int idx, const char *verify_type, sd_json_variant **ret); int cryptsetup_get_token_as_json(struct crypt_device *cd, int idx, const char *verify_type, sd_json_variant **ret);
int cryptsetup_add_token_json(struct crypt_device *cd, sd_json_variant *v); int cryptsetup_add_token_json(struct crypt_device *cd, sd_json_variant *v);
#else
/* If libcryptsetup is not available, let's at least define the basic type and NOP destructors for it, to
* make a little bit less #ifdeferry necessary in main programs. */
struct crypt_device;
static inline void sym_crypt_free(struct crypt_device* cd) {}
static inline void sym_crypt_freep(struct crypt_device** cd) {}
#endif #endif
int dlopen_cryptsetup(void); int dlopen_cryptsetup(void);

View File

@ -2668,13 +2668,11 @@ static int verity_can_reuse(
memcmp(root_hash_existing, verity->root_hash, verity->root_hash_size) != 0) memcmp(root_hash_existing, verity->root_hash, verity->root_hash_size) != 0)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Error opening verity device, it already exists but root hashes are different."); return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Error opening verity device, it already exists but root hashes are different.");
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
/* Ensure that, if signatures are supported, we only reuse the device if the previous mount used the /* Ensure that, if signatures are supported, we only reuse the device if the previous mount used the
* same settings, so that a previous unsigned mount will not be reused if the user asks to use * same settings, so that a previous unsigned mount will not be reused if the user asks to use
* signing for the new one, and vice versa. */ * signing for the new one, and vice versa. */
if (!!verity->root_hash_sig != !!(crypt_params.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE)) if (!!verity->root_hash_sig != !!(crypt_params.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Error opening verity device, it already exists but signature settings are not the same."); return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Error opening verity device, it already exists but signature settings are not the same.");
#endif
*ret_cd = TAKE_PTR(cd); *ret_cd = TAKE_PTR(cd);
return 0; return 0;
@ -2820,7 +2818,6 @@ static int do_crypt_activate_verity(
check_signature = false; check_signature = false;
if (check_signature) { if (check_signature) {
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
/* First, if we have support for signed keys in the kernel, then try that first. */ /* First, if we have support for signed keys in the kernel, then try that first. */
r = sym_crypt_activate_by_signed_key( r = sym_crypt_activate_by_signed_key(
cd, cd,
@ -2842,11 +2839,6 @@ static int do_crypt_activate_verity(
* -ENOKEY, which means "password required, but I have none". */ * -ENOKEY, which means "password required, but I have none". */
if (r == -ENOKEY) if (r == -ENOKEY)
r = -EDESTADDRREQ; r = -EDESTADDRREQ;
#else
log_debug("Activation of verity device with signature requested, but not supported via the kernel by %s due to missing crypt_activate_by_signed_key(), trying userspace validation instead.",
program_invocation_short_name);
r = 0; /* Set for the propagation below */
#endif
/* So this didn't work via the kernel, then let's try userspace validation instead. If that /* So this didn't work via the kernel, then let's try userspace validation instead. If that
* works we'll try to activate without telling the kernel the signature. */ * works we'll try to activate without telling the kernel the signature. */

View File

@ -390,6 +390,19 @@ _noreturn_ void log_test_failed_internal(const char *file, int line, const char
}) })
#endif #endif
#ifdef __COVERITY__
# define ASSERT_STRNEQ(expr1, expr2, n) __coverity_check__(strneq_ptr((expr1), (expr2), (n)))
#else
# define ASSERT_STRNEQ(expr1, expr2, n) \
({ \
const char *_expr1 = (expr1), *_expr2 = (expr2); \
size_t _n = (n); \
if (!strneq_ptr(_expr1, _expr2, _n)) \
log_test_failed("Expected \"%s == %s\", got \"%s != %s\" (first %zu characters)", \
#expr1, #expr2, strnull(_expr1), strnull(_expr2), _n); \
})
#endif
#ifdef __COVERITY__ #ifdef __COVERITY__
# define ASSERT_PTR_EQ(expr1, expr2) __coverity_check__((expr1) == (expr2)) # define ASSERT_PTR_EQ(expr1, expr2) __coverity_check__((expr1) == (expr2))
#else #else

View File

@ -2,6 +2,7 @@
#include "alloc-util.h" #include "alloc-util.h"
#include "capability-list.h" #include "capability-list.h"
#include "capability-util.h"
#include "format-util.h" #include "format-util.h"
#include "glyph-util.h" #include "glyph-util.h"
#include "hashmap.h" #include "hashmap.h"
@ -404,7 +405,7 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
printf(" Access Mode: 0%03o\n", user_record_access_mode(hr)); printf(" Access Mode: 0%03o\n", user_record_access_mode(hr));
uint64_t caps = user_record_capability_bounding_set(hr); uint64_t caps = user_record_capability_bounding_set(hr);
if (caps != UINT64_MAX) { if (caps != CAP_MASK_UNSET) {
_cleanup_free_ char *scaps = NULL; _cleanup_free_ char *scaps = NULL;
(void) capability_set_to_string_negative(caps, &scaps); (void) capability_set_to_string_negative(caps, &scaps);
@ -412,7 +413,7 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
} }
caps = user_record_capability_ambient_set(hr); caps = user_record_capability_ambient_set(hr);
if (caps != UINT64_MAX) { if (caps != CAP_MASK_UNSET) {
_cleanup_free_ char *scaps = NULL; _cleanup_free_ char *scaps = NULL;
(void) capability_set_to_string(caps, &scaps); (void) capability_set_to_string(caps, &scaps);

View File

@ -4,27 +4,119 @@
#include "varlink-io.systemd.Repart.h" #include "varlink-io.systemd.Repart.h"
static SD_VARLINK_DEFINE_ENUM_TYPE(
ProgressPhase,
SD_VARLINK_DEFINE_ENUM_VALUE(loading_definitions),
SD_VARLINK_DEFINE_ENUM_VALUE(loading_table),
SD_VARLINK_DEFINE_ENUM_VALUE(opening_copy_block_sources),
SD_VARLINK_DEFINE_ENUM_VALUE(acquiring_partition_labels),
SD_VARLINK_DEFINE_ENUM_VALUE(minimizing),
SD_VARLINK_DEFINE_ENUM_VALUE(placing),
SD_VARLINK_DEFINE_ENUM_VALUE(wiping_disk),
SD_VARLINK_DEFINE_ENUM_VALUE(wiping_partition),
SD_VARLINK_DEFINE_ENUM_VALUE(copying_partition),
SD_VARLINK_DEFINE_ENUM_VALUE(formatting_partition),
SD_VARLINK_DEFINE_ENUM_VALUE(adjusting_partition),
SD_VARLINK_DEFINE_ENUM_VALUE(writing_table),
SD_VARLINK_DEFINE_ENUM_VALUE(rereading_table));
static SD_VARLINK_DEFINE_ENUM_TYPE(
EmptyMode,
SD_VARLINK_FIELD_COMMENT("Refuse to operate on disks without an existing partition table"),
SD_VARLINK_DEFINE_ENUM_VALUE(refuse),
SD_VARLINK_FIELD_COMMENT("Create a new partition table if one doesn't already exist on disk"),
SD_VARLINK_DEFINE_ENUM_VALUE(allow),
SD_VARLINK_FIELD_COMMENT("Refuse to operate on disks with an existing partition table, and create a new table if none exists"),
SD_VARLINK_DEFINE_ENUM_VALUE(require),
SD_VARLINK_FIELD_COMMENT("Always create a new partition table, potentially overwriting an existing table"),
SD_VARLINK_DEFINE_ENUM_VALUE(force));
static SD_VARLINK_DEFINE_METHOD_FULL(
Run,
SD_VARLINK_SUPPORTS_MORE,
SD_VARLINK_FIELD_COMMENT("Full path to the block device node to operate on. If omitted, dryRun must be true, in which case the minimal disk size is determined."),
SD_VARLINK_DEFINE_INPUT(node, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Decides whether to install the OS in addition to what is already on it, or if it shall be erased."),
SD_VARLINK_DEFINE_INPUT_BY_TYPE(empty, EmptyMode, 0),
SD_VARLINK_FIELD_COMMENT("If true this will ponder if the installation would fit, but does not actually write anything to disk. Must be set to false to actually make changes."),
SD_VARLINK_DEFINE_INPUT(dryRun, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("The seed value to derive partition and file system UUIDs from"),
SD_VARLINK_DEFINE_INPUT(seed, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Path to directory containing definition files."),
SD_VARLINK_DEFINE_INPUT(definitions, SD_VARLINK_STRING, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("If true, automatically defer creation of all partitions whose label is \"empty\"."),
SD_VARLINK_DEFINE_INPUT(deferPartitionsEmpty, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("If true, automatically defer creation of all partitions which are marked for factory reset."),
SD_VARLINK_DEFINE_INPUT(deferPartitionsFactoryReset, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("In dry-run mode returns the minimal disk size required."),
SD_VARLINK_DEFINE_OUTPUT(minimalSizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("In dry-run mode returns the size of the selected block device."),
SD_VARLINK_DEFINE_OUTPUT(currentSizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("If used with the 'more' flag, a phase identifier is sent in progress updates."),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(phase, ProgressPhase, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("If used with the 'more' flag, an object identifier string is sent in progress updates."),
SD_VARLINK_DEFINE_OUTPUT(object, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("If used with the 'more' flag, a progress percentrage (specific to the work done for the specified phase+object is sent in progress updates."),
SD_VARLINK_DEFINE_OUTPUT(progress, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD( static SD_VARLINK_DEFINE_METHOD(
ListCandidateDevices, ListCandidateDevices,
SD_VARLINK_FIELD_COMMENT("The device node path of the block device."),
SD_VARLINK_DEFINE_OUTPUT(node, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Control whether to include the root disk of the currently booted OS in the list. Defaults to false, i.e. the root disk is included."), SD_VARLINK_FIELD_COMMENT("Control whether to include the root disk of the currently booted OS in the list. Defaults to false, i.e. the root disk is included."),
SD_VARLINK_DEFINE_INPUT(ignoreRoot, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_INPUT(ignoreRoot, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Control whether to include block devices with zero size in the list, i.e. typically block devices without any inserted medium. Defaults to false, i.e. empty block devices are included."), SD_VARLINK_FIELD_COMMENT("Control whether to include block devices with zero size in the list, i.e. typically block devices without any inserted medium. Defaults to false, i.e. empty block devices are included."),
SD_VARLINK_DEFINE_INPUT(ignoreEmpty, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_INPUT(ignoreEmpty, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The device node path of the block device."),
SD_VARLINK_DEFINE_OUTPUT(node, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("List of symlinks pointing to the device node, if any."), SD_VARLINK_FIELD_COMMENT("List of symlinks pointing to the device node, if any."),
SD_VARLINK_DEFINE_OUTPUT(symlinks, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_OUTPUT(symlinks, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The Linux kernel disk sequence number identifying the medium."), SD_VARLINK_FIELD_COMMENT("The Linux kernel disk sequence number identifying the medium."),
SD_VARLINK_DEFINE_OUTPUT(diskseq, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_OUTPUT(diskseq, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The size of the block device in bytes."), SD_VARLINK_FIELD_COMMENT("The size of the block device in bytes."),
SD_VARLINK_DEFINE_OUTPUT(sizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE)); SD_VARLINK_DEFINE_OUTPUT(sizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The device vendor string if known"),
SD_VARLINK_DEFINE_OUTPUT(vendor, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The device model string if known"),
SD_VARLINK_DEFINE_OUTPUT(model, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The subsystem the block device belongs to if known"),
SD_VARLINK_DEFINE_OUTPUT(subsystem, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_ERROR(NoCandidateDevices); static SD_VARLINK_DEFINE_ERROR(NoCandidateDevices);
static SD_VARLINK_DEFINE_ERROR(ConflictingDiskLabelPresent);
static SD_VARLINK_DEFINE_ERROR(
InsufficientFreeSpace,
SD_VARLINK_FIELD_COMMENT("Minimal size of the disk required for the installation."),
SD_VARLINK_DEFINE_FIELD(minimalSizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Additional free space needed on the selected disk."),
SD_VARLINK_DEFINE_FIELD(needFreeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Size of the selected block device."),
SD_VARLINK_DEFINE_FIELD(currentSizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_ERROR(
DiskTooSmall,
SD_VARLINK_FIELD_COMMENT("Minimal size of the disk required for the installation."),
SD_VARLINK_DEFINE_FIELD(minimalSizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Actual size of the selected block device."),
SD_VARLINK_DEFINE_FIELD(currentSizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_INTERFACE( SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Repart, io_systemd_Repart,
"io.systemd.Repart", "io.systemd.Repart",
SD_VARLINK_INTERFACE_COMMENT("API for declaratively re-partitioning disks using systemd-repart."), SD_VARLINK_INTERFACE_COMMENT("API for declaratively re-partitioning disks using systemd-repart."),
SD_VARLINK_SYMBOL_COMMENT("Behaviors for disks that are completely empty (i.e. don't have a partition table yet)"),
&vl_type_EmptyMode,
SD_VARLINK_SYMBOL_COMMENT("Progress phase identifiers. Note that we might add more phases here, and thus identifiers. Frontends can choose to display the phase to the user in some human readable form, or not do that, but if they do it and they receive a notification for a so far unknown phase, they should just ignore it."),
&vl_type_ProgressPhase,
SD_VARLINK_SYMBOL_COMMENT("Invoke the actual repartitioning operation, either in dry-run mode or for real. If invoked with 'more' enabled will report progress, otherwise will just report completion."),
&vl_method_Run,
SD_VARLINK_SYMBOL_COMMENT("An incompatible disk label present, and not told to erase it."),
&vl_error_ConflictingDiskLabelPresent,
SD_VARLINK_SYMBOL_COMMENT("The target disk has insufficient free space to fit all requested partitions. (But the disk would fit, if emptied.)"),
&vl_error_InsufficientFreeSpace,
SD_VARLINK_SYMBOL_COMMENT("The target disk is too small to fit the installation. (Regardless if emtied or not.)"),
&vl_error_DiskTooSmall,
SD_VARLINK_SYMBOL_COMMENT("Return a list of candidate block devices, i.e. that support partition scanning and other requirements for successful operation."), SD_VARLINK_SYMBOL_COMMENT("Return a list of candidate block devices, i.e. that support partition scanning and other requirements for successful operation."),
&vl_method_ListCandidateDevices, &vl_method_ListCandidateDevices,
SD_VARLINK_SYMBOL_COMMENT("Not a single candidate block device could be found."), SD_VARLINK_SYMBOL_COMMENT("Not a single candidate block device could be found."),

View File

@ -44,7 +44,7 @@ int verb_add_dependency(int argc, char *argv[], void *userdata) {
else else
assert_not_reached(); assert_not_reached();
if (install_client_side()) { if (install_client_side() != INSTALL_CLIENT_SIDE_NO) {
InstallChange *changes = NULL; InstallChange *changes = NULL;
size_t n_changes = 0; size_t n_changes = 0;

View File

@ -370,7 +370,8 @@ int verb_edit(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return r; return r;
if (!arg_no_reload && !install_client_side()) { if (!arg_no_reload &&
install_client_side() == INSTALL_CLIENT_SIDE_NO) {
r = daemon_reload(ACTION_RELOAD, /* graceful= */ false); r = daemon_reload(ACTION_RELOAD, /* graceful= */ false);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -103,7 +103,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
/* If the operation was fully executed by the SysV compat, let's finish early */ /* If the operation was fully executed by the SysV compat, let's finish early */
if (strv_isempty(names)) { if (strv_isempty(names)) {
if (arg_no_reload || install_client_side()) if (arg_no_reload || install_client_side() != INSTALL_CLIENT_SIDE_NO)
return 0; return 0;
r = daemon_reload(ACTION_RELOAD, /* graceful= */ false); r = daemon_reload(ACTION_RELOAD, /* graceful= */ false);
@ -119,41 +119,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return r; return r;
if (install_client_side()) { if (install_client_side() == INSTALL_CLIENT_SIDE_NO) {
UnitFileFlags flags;
InstallChange *changes = NULL;
size_t n_changes = 0;
CLEANUP_ARRAY(changes, n_changes, install_changes_free);
flags = unit_file_flags_from_args();
if (streq(verb, "enable")) {
r = unit_file_enable(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
carries_install_info = r;
} else if (streq(verb, "disable")) {
r = unit_file_disable(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
carries_install_info = r;
} else if (streq(verb, "reenable")) {
r = unit_file_reenable(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
carries_install_info = r;
} else if (streq(verb, "link"))
r = unit_file_link(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
else if (streq(verb, "preset"))
r = unit_file_preset(arg_runtime_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes);
else if (streq(verb, "mask"))
r = unit_file_mask(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
else if (streq(verb, "unmask"))
r = unit_file_unmask(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
else if (streq(verb, "revert"))
r = unit_file_revert(arg_runtime_scope, arg_root, names, &changes, &n_changes);
else
assert_not_reached();
install_changes_dump(r, verb, changes, n_changes, arg_quiet);
if (r < 0)
return r;
} else {
_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;
bool expect_carries_install_info = false; bool expect_carries_install_info = false;
@ -275,6 +241,40 @@ int verb_enable(int argc, char *argv[], void *userdata) {
if (warn_trigger_operation && !arg_quiet && !arg_no_warn) if (warn_trigger_operation && !arg_quiet && !arg_no_warn)
STRV_FOREACH(unit, names) STRV_FOREACH(unit, names)
warn_triggering_units(bus, *unit, warn_trigger_operation, warn_trigger_ignore_masked); warn_triggering_units(bus, *unit, warn_trigger_operation, warn_trigger_ignore_masked);
} else {
UnitFileFlags flags;
InstallChange *changes = NULL;
size_t n_changes = 0;
CLEANUP_ARRAY(changes, n_changes, install_changes_free);
flags = unit_file_flags_from_args();
if (streq(verb, "enable")) {
r = unit_file_enable(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
carries_install_info = r;
} else if (streq(verb, "disable")) {
r = unit_file_disable(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
carries_install_info = r;
} else if (streq(verb, "reenable")) {
r = unit_file_reenable(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
carries_install_info = r;
} else if (streq(verb, "link"))
r = unit_file_link(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
else if (streq(verb, "preset"))
r = unit_file_preset(arg_runtime_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes);
else if (streq(verb, "mask"))
r = unit_file_mask(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
else if (streq(verb, "unmask"))
r = unit_file_unmask(arg_runtime_scope, flags, arg_root, names, &changes, &n_changes);
else if (streq(verb, "revert"))
r = unit_file_revert(arg_runtime_scope, arg_root, names, &changes, &n_changes);
else
assert_not_reached();
install_changes_dump(r, verb, changes, n_changes, arg_quiet);
if (r < 0)
return r;
} }
if (carries_install_info == 0 && !ignore_carries_install_info) if (carries_install_info == 0 && !ignore_carries_install_info)
@ -334,7 +334,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
if (arg_now) { if (arg_now) {
_cleanup_strv_free_ char **new_args = NULL; _cleanup_strv_free_ char **new_args = NULL;
const char *start_verb; const char *start_verb;
bool accept_path, prohibit_templates; bool accept_path, prohibit_templates, dead_ok = false;
if (streq(verb, "enable")) { if (streq(verb, "enable")) {
start_verb = "start"; start_verb = "start";
@ -344,6 +344,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
start_verb = "stop"; start_verb = "stop";
accept_path = false; accept_path = false;
prohibit_templates = false; prohibit_templates = false;
dead_ok = true; /* If the service is not running anyway, no need to stop it. */
} else if (streq(verb, "reenable")) { } else if (streq(verb, "reenable")) {
/* Note that we use try-restart here. This matches the semantics of reenable better, /* Note that we use try-restart here. This matches the semantics of reenable better,
* and allows us to glob template units. */ * and allows us to glob template units. */
@ -354,9 +355,20 @@ int verb_enable(int argc, char *argv[], void *userdata) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--now can only be used with verb enable, disable, reenable, or mask."); "--now can only be used with verb enable, disable, reenable, or mask.");
if (install_client_side()) switch (install_client_side()) {
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), case INSTALL_CLIENT_SIDE_NO:
"--now cannot be used when systemd is not running or in conjunction with --root=/--global, refusing."); break;
case INSTALL_CLIENT_SIDE_OVERRIDE:
case INSTALL_CLIENT_SIDE_OFFLINE:
case INSTALL_CLIENT_SIDE_NOT_BOOTED:
if (!dead_ok)
log_warning("Cannot %s unit with --now when systemd is not running, ignoring.", start_verb);
return 0;
case INSTALL_CLIENT_SIDE_ARG_ROOT:
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "--now cannot be used with --root=.");
case INSTALL_CLIENT_SIDE_GLOBAL_SCOPE:
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "--now cannot be used with --global.");
}
assert(bus); assert(bus);

View File

@ -82,7 +82,7 @@ int verb_is_enabled(int argc, char *argv[], void *userdata) {
not_found = r == 0; /* Doesn't have SysV support or SYSV_UNIT_NOT_FOUND */ not_found = r == 0; /* Doesn't have SysV support or SYSV_UNIT_NOT_FOUND */
enabled = r == SYSV_UNIT_ENABLED; enabled = r == SYSV_UNIT_ENABLED;
if (install_client_side()) if (install_client_side() != INSTALL_CLIENT_SIDE_NO)
STRV_FOREACH(name, names) { STRV_FOREACH(name, names) {
UnitFileState state; UnitFileState state;

View File

@ -180,7 +180,7 @@ int verb_list_unit_files(int argc, char *argv[], void *userdata) {
unsigned c = 0; unsigned c = 0;
int r; int r;
if (install_client_side()) { if (install_client_side() != INSTALL_CLIENT_SIDE_NO) {
unsigned n_units; unsigned n_units;
r = unit_file_get_list(arg_runtime_scope, arg_root, arg_states, strv_skip(argv, 1), &h); r = unit_file_get_list(arg_runtime_scope, arg_root, arg_states, strv_skip(argv, 1), &h);

View File

@ -19,7 +19,7 @@ int verb_preset_all(int argc, char *argv[], void *userdata) {
if (should_bypass("SYSTEMD_PRESET")) if (should_bypass("SYSTEMD_PRESET"))
return 0; return 0;
if (install_client_side()) { if (install_client_side() != INSTALL_CLIENT_SIDE_NO) {
InstallChange *changes = NULL; InstallChange *changes = NULL;
size_t n_changes = 0; size_t n_changes = 0;

View File

@ -58,7 +58,7 @@ static void emit_cmdline_warning(void) {
static int determine_default(char **ret_name) { static int determine_default(char **ret_name) {
int r; int r;
if (install_client_side()) { if (install_client_side() != INSTALL_CLIENT_SIDE_NO) {
r = unit_file_get_default(arg_runtime_scope, arg_root, ret_name); r = unit_file_get_default(arg_runtime_scope, arg_root, ret_name);
if (r == -ERFKILL) if (r == -ERFKILL)
return log_error_errno(r, "Failed to get default target: Unit file is masked."); return log_error_errno(r, "Failed to get default target: Unit file is masked.");
@ -116,7 +116,7 @@ int verb_set_default(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m"); return log_error_errno(r, "Failed to mangle unit name: %m");
if (install_client_side()) { if (install_client_side() != INSTALL_CLIENT_SIDE_NO) {
InstallChange *changes = NULL; InstallChange *changes = NULL;
size_t n_changes = 0; size_t n_changes = 0;

View File

@ -523,7 +523,7 @@ int unit_find_paths(
/* Go via the bus to acquire the path, unless we are explicitly told not to, or when the unit name is a template */ /* Go via the bus to acquire the path, unless we are explicitly told not to, or when the unit name is a template */
if (!force_client_side && if (!force_client_side &&
!install_client_side() && install_client_side() == INSTALL_CLIENT_SIDE_NO &&
!unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) { !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
_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_free_ char *load_state = NULL, *dbus_path = NULL; _cleanup_free_ char *load_state = NULL, *dbus_path = NULL;
@ -880,26 +880,27 @@ bool output_show_unit(const UnitInfo *u, char **patterns) {
return true; return true;
} }
bool install_client_side(void) { InstallClientSide install_client_side(void) {
/* Decides when to execute enable/disable/... operations client-side rather than server-side. */ /* Decides whether to execute enable/disable/… client-side offline operation rather than
* server-side. */
if (running_in_chroot_or_offline())
return true;
if (sd_booted() <= 0)
return true;
if (!isempty(arg_root))
return true;
if (arg_runtime_scope == RUNTIME_SCOPE_GLOBAL)
return true;
/* Unsupported environment variable, mostly for debugging purposes */ /* Unsupported environment variable, mostly for debugging purposes */
if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0) if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
return true; return INSTALL_CLIENT_SIDE_OVERRIDE;
return false; if (!isempty(arg_root))
return INSTALL_CLIENT_SIDE_ARG_ROOT;
if (running_in_chroot_or_offline())
return INSTALL_CLIENT_SIDE_OFFLINE;
if (sd_booted() <= 0)
return INSTALL_CLIENT_SIDE_NOT_BOOTED;
if (arg_runtime_scope == RUNTIME_SCOPE_GLOBAL)
return INSTALL_CLIENT_SIDE_GLOBAL_SCOPE;
return INSTALL_CLIENT_SIDE_NO;
} }
int output_table(Table *table) { int output_table(Table *table) {

View File

@ -69,7 +69,16 @@ int unit_get_dependencies(sd_bus *bus, const char *name, char ***ret);
const char* unit_type_suffix(const char *unit); const char* unit_type_suffix(const char *unit);
bool output_show_unit(const UnitInfo *u, char **patterns); bool output_show_unit(const UnitInfo *u, char **patterns);
bool install_client_side(void); typedef enum InstallClientSide {
INSTALL_CLIENT_SIDE_NO = 0,
INSTALL_CLIENT_SIDE_OVERRIDE,
INSTALL_CLIENT_SIDE_ARG_ROOT,
INSTALL_CLIENT_SIDE_OFFLINE,
INSTALL_CLIENT_SIDE_NOT_BOOTED,
INSTALL_CLIENT_SIDE_GLOBAL_SCOPE,
} InstallClientSide;
InstallClientSide install_client_side(void);
int output_table(Table *table); int output_table(Table *table);

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
#include <math.h> #include <math.h>
#include <sys/socket.h> #include <sys/socket.h>
#include "capability-util.h"
#include "locale-util.h" #include "locale-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "tests.h" #include "tests.h"
@ -888,4 +889,127 @@ TEST(nft_identifier_valid) {
ASSERT_FALSE(nft_identifier_valid(s)); ASSERT_FALSE(nft_identifier_valid(s));
} }
static uint64_t make_cap(int cap) {
return ((uint64_t) 1ULL << (uint64_t) cap);
}
TEST(parse_capability_set) {
uint64_t current;
/* Empty string resets to CAP_MASK_UNSET */
current = 0x1234;
ASSERT_OK(parse_capability_set("", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, CAP_MASK_UNSET);
/* Single capability by name - replaces if current == initial */
current = CAP_MASK_UNSET;
ASSERT_OK(parse_capability_set("cap_chown", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN));
/* Single capability by name - merges if current != initial */
current = make_cap(CAP_SETUID);
ASSERT_OK(parse_capability_set("cap_chown", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN) | make_cap(CAP_SETUID));
/* Multiple capabilities - replaces when current == initial */
current = CAP_MASK_UNSET;
ASSERT_OK(parse_capability_set("cap_chown cap_setuid", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN) | make_cap(CAP_SETUID));
/* Multiple capabilities - merges when current != initial */
current = make_cap(CAP_SETGID);
ASSERT_OK(parse_capability_set("cap_chown cap_setuid", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN) | make_cap(CAP_SETUID) | make_cap(CAP_SETGID));
/* Inverted capabilities - replaces with complement when current == initial */
current = CAP_MASK_UNSET;
ASSERT_OK(parse_capability_set("~cap_chown", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, all_capabilities() & ~make_cap(CAP_CHOWN));
/* Inverted capabilities - removes from current when current != initial */
current = all_capabilities();
ASSERT_OK(parse_capability_set("~cap_chown", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, all_capabilities() & ~make_cap(CAP_CHOWN));
/* Inverted multiple capabilities */
current = all_capabilities();
ASSERT_OK(parse_capability_set("~cap_chown cap_setuid", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, all_capabilities() & ~(make_cap(CAP_CHOWN) | make_cap(CAP_SETUID)));
/* Tilde alone resets to all capabilities complement (i.e., empty) */
current = 0x1234;
ASSERT_OK(parse_capability_set("~", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, all_capabilities());
/* Sequential calls - testing merge behavior */
current = CAP_MASK_UNSET;
ASSERT_OK(parse_capability_set("cap_chown", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN));
ASSERT_OK(parse_capability_set("cap_setuid", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN) | make_cap(CAP_SETUID));
/* Sequential calls with invert */
current = all_capabilities();
ASSERT_OK(parse_capability_set("~cap_chown", CAP_MASK_UNSET, &current));
ASSERT_OK(parse_capability_set("~cap_setuid", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, all_capabilities() & ~(make_cap(CAP_CHOWN) | make_cap(CAP_SETUID)));
/* Numeric capability */
current = CAP_MASK_UNSET;
ASSERT_OK(parse_capability_set("0", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(0));
current = CAP_MASK_UNSET;
ASSERT_OK(parse_capability_set("5", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(5));
/* Mixed numeric and named capabilities */
current = CAP_MASK_UNSET;
ASSERT_OK(parse_capability_set("0 cap_chown 5", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(0) | make_cap(CAP_CHOWN) | make_cap(5));
/* Invalid capabilities are ignored but function returns 0 */
current = CAP_MASK_UNSET;
ASSERT_OK_ZERO(parse_capability_set("invalid_cap", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, 0U);
/* Mix of valid and invalid capabilities */
current = CAP_MASK_UNSET;
ASSERT_OK_ZERO(parse_capability_set("cap_chown invalid_cap cap_setuid", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN) | make_cap(CAP_SETUID));
/* Case insensitivity */
current = CAP_MASK_UNSET;
ASSERT_OK(parse_capability_set("CAP_CHOWN", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN));
current = CAP_MASK_UNSET;
ASSERT_OK(parse_capability_set("CaP_ChOwN", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN));
/* Inverted with invalid capabilities */
current = all_capabilities();
ASSERT_OK_ZERO(parse_capability_set("~invalid_cap", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, all_capabilities());
/* Inverted with mix of valid and invalid */
current = all_capabilities();
ASSERT_OK_ZERO(parse_capability_set("~cap_chown invalid_cap", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, all_capabilities() & ~make_cap(CAP_CHOWN));
/* Whitespace handling */
current = 0;
ASSERT_OK(parse_capability_set(" cap_chown cap_setuid ", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN) | make_cap(CAP_SETUID));
/* Testing that initial value determines replace vs merge */
current = make_cap(CAP_SETGID);
ASSERT_OK(parse_capability_set("cap_chown", make_cap(CAP_SETGID), &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN)); /* Replace because current == initial */
current = make_cap(CAP_SETGID);
ASSERT_OK(parse_capability_set("cap_chown", CAP_MASK_UNSET, &current));
ASSERT_EQ(current, make_cap(CAP_CHOWN) | make_cap(CAP_SETGID)); /* Merge because current != initial */
}
DEFINE_TEST_MAIN(LOG_INFO); DEFINE_TEST_MAIN(LOG_INFO);

View File

@ -101,10 +101,6 @@ static int parse_roothashsig_option(const char *option, bool strict) {
else else
return false; return false;
if (!HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Activation of verity device with signature requested, but cryptsetup does not support crypt_activate_by_signed_key().");
free_and_replace(arg_root_hash_signature, rhs); free_and_replace(arg_root_hash_signature, rhs);
arg_root_hash_signature_size = rhss; arg_root_hash_signature_size = rhss;
arg_root_hash_signature_auto = set_auto; arg_root_hash_signature_auto = set_auto;
@ -416,7 +412,6 @@ static int verb_attach(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to configure data device: %m"); return log_error_errno(r, "Failed to configure data device: %m");
if (arg_root_hash_signature_size > 0) { if (arg_root_hash_signature_size > 0) {
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
r = crypt_activate_by_signed_key(cd, volume, rh, rh_size, arg_root_hash_signature, arg_root_hash_signature_size, arg_activate_flags); r = crypt_activate_by_signed_key(cd, volume, rh, rh_size, arg_root_hash_signature, arg_root_hash_signature_size, arg_activate_flags);
if (r < 0) { if (r < 0) {
log_info_errno(r, "Unable to activate verity device '%s' with root hash signature (%m), retrying without.", volume); log_info_errno(r, "Unable to activate verity device '%s' with root hash signature (%m), retrying without.", volume);
@ -427,9 +422,6 @@ static int verb_attach(int argc, char *argv[], void *userdata) {
log_info("Activation of verity device '%s' succeeded without root hash signature.", volume); log_info("Activation of verity device '%s' succeeded without root hash signature.", volume);
} }
#else
assert_not_reached();
#endif
} else } else
r = crypt_activate_by_volume_key(cd, volume, rh, rh_size, arg_activate_flags); r = crypt_activate_by_volume_key(cd, volume, rh, rh_size, arg_activate_flags);
if (r < 0) if (r < 0)

View File

@ -78,6 +78,17 @@ fi
systemd-dissect --umount "$IMAGE_DIR/mount" systemd-dissect --umount "$IMAGE_DIR/mount"
systemd-dissect --umount "$IMAGE_DIR/mount2" systemd-dissect --umount "$IMAGE_DIR/mount2"
# Ensure the deferred close flag is set up correctly and we don't leak verity devices
# when sharing is disabled
set +o pipefail
# The devices are named 'loopXYZ-verity' when sharing is disabled
n_before=$(dmsetup ls | grep loop | grep -c verity || true)
SYSTEMD_VERITY_SHARING=0 systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount"
test $((n_before + 1)) -eq "$(dmsetup ls | grep loop | grep -c verity || true)"
umount -R "$IMAGE_DIR/mount"
test "$n_before" -eq "$(dmsetup ls | grep loop | grep -c verity || true)"
set -o pipefail
# Test BindLogSockets= # Test BindLogSockets=
systemd-run --wait -p RootImage="$MINIMAL_IMAGE.raw" mountpoint /run/systemd/journal/socket systemd-run --wait -p RootImage="$MINIMAL_IMAGE.raw" mountpoint /run/systemd/journal/socket
(! systemd-run --wait -p RootImage="$MINIMAL_IMAGE.raw" -p BindLogSockets=no ls /run/systemd/journal/socket) (! systemd-run --wait -p RootImage="$MINIMAL_IMAGE.raw" -p BindLogSockets=no ls /run/systemd/journal/socket)

View File

@ -141,6 +141,12 @@ SizeMaxBytes=64M
PaddingMinBytes=92M PaddingMinBytes=92M
EOF EOF
systemd-repart --definitions="$defs" \
--dry-run=yes \
--seed="$seed" \
--include-partitions=home,swap \
"-"
systemd-repart --offline="$OFFLINE" \ systemd-repart --offline="$OFFLINE" \
--definitions="$defs" \ --definitions="$defs" \
--dry-run=no \ --dry-run=no \
@ -1690,6 +1696,70 @@ testcase_varlink_list_devices() {
varlinkctl call /run/systemd/io.systemd.Repart --graceful=io.systemd.Repart.NoCandidateDevices --collect io.systemd.Repart.ListCandidateDevices '{"ignoreEmpty":true,"ignoreRoot":true}' varlinkctl call /run/systemd/io.systemd.Repart --graceful=io.systemd.Repart.NoCandidateDevices --collect io.systemd.Repart.ListCandidateDevices '{"ignoreEmpty":true,"ignoreRoot":true}'
} }
testcase_get_size() {
local defs
defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs'" RETURN
tee "$defs/a.conf" <<EOF
[Partition]
Type=root
SizeMinBytes=15M
EOF
tee "$defs/b.conf" <<EOF
[Partition]
Type=linux-generic
SizeMinBytes=23M
EOF
output="$(systemd-repart --definitions="$defs" - 2>&1)"
assert_in "Automatically determined minimal disk image size as 39M." "$output"
}
testcase_varlink_run() {
local defs
defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
tee "$defs/a.conf" <<EOF
[Partition]
Type=root
Format=empty
EOF
tee "$defs/b.conf" <<EOF
[Partition]
Type=linux-generic
Format=empty
EOF
systemd-repart --pretty=yes \
--definitions "$defs" \
--empty=create \
--size=50M \
--seed="$seed" \
--dry-run=no \
--offline=yes \
"$imgs/disk1.img"
REPART="$(which systemd-repart)"
truncate -s 50M "$imgs/disk2.img"
varlinkctl call "$REPART" io.systemd.Repart.Run '{"definitions":["'"$defs"'"],"empty":"force","seed":"'"$seed"'","dryRun":false,"node":"'"$imgs/disk2.img"'"}'
# Compare that the version from the command line and via Varlink result in the bit exact same output
cmp "$imgs/disk1.img" "$imgs/disk2.img"
# Try once more, this time with progress info
truncate -s 50M "$imgs/disk3.img"
varlinkctl --more --collect call "$REPART" io.systemd.Repart.Run '{"definitions":["'"$defs"'"],"empty":"force","seed":"'"$seed"'","dryRun":false,"node":"'"$imgs/disk3.img"'"}'
cmp "$imgs/disk1.img" "$imgs/disk3.img"
}
OFFLINE="yes" OFFLINE="yes"
run_testcases run_testcases