mirror of
https://github.com/systemd/systemd
synced 2025-11-16 23:34:46 +01:00
Compare commits
30 Commits
25a507d290
...
ee3cd7890d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee3cd7890d | ||
|
|
d714edd26c | ||
|
|
a983cf253f | ||
|
|
d1aa3860b2 | ||
|
|
5f076e44fe | ||
|
|
ea94a05f8a | ||
|
|
2103067f25 | ||
|
|
63b9c8611d | ||
|
|
0f9d58cc36 | ||
|
|
1c76e204d3 | ||
|
|
15734190c7 | ||
|
|
2ecfea7491 | ||
|
|
0eab6d2960 | ||
|
|
a47cbb6d9d | ||
|
|
eccd8d9a57 | ||
|
|
b64eb98054 | ||
|
|
633a4b8839 | ||
|
|
db1f63463a | ||
|
|
6afaa7fb3a | ||
|
|
f8c33b1274 | ||
|
|
93317e9c17 | ||
|
|
786aaed943 | ||
|
|
e01f8990f1 | ||
|
|
3cc3b469cc | ||
|
|
10e82fde7b | ||
|
|
1a3b3c57c6 | ||
|
|
10fc43e504 | ||
|
|
7517e41a49 | ||
|
|
77a1cc8fa0 | ||
|
|
0ff5985176 |
@ -828,6 +828,29 @@ manpages = [
|
||||
'sd_journal_seek_tail'],
|
||||
''],
|
||||
['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',
|
||||
'3',
|
||||
['SD_LISTEN_FDS_START', 'sd_listen_fds_with_names'],
|
||||
|
||||
364
man/sd_json_dispatch_string.xml
Normal file
364
man/sd_json_dispatch_string.xml
Normal 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 <systemd/sd-varlink.h></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 > 0, == 0 or < 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>
|
||||
@ -26,7 +26,7 @@
|
||||
<cmdsynopsis>
|
||||
<command>systemd-repart</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
<arg choice="opt" rep="repeat"><replaceable><optional>BLOCKDEVICE</optional></replaceable></arg>
|
||||
<arg choice="opt">BLOCKDEVICE</arg>
|
||||
</cmdsynopsis>
|
||||
|
||||
<para><filename>systemd-repart.service</filename></para>
|
||||
@ -35,10 +35,10 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-repart</command> creates partition tables, and adds or grows partitions,
|
||||
based on the configuration files described in
|
||||
<citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
</para>
|
||||
<para><command>systemd-repart</command> creates partition tables, and adds or grows partitions, based on
|
||||
the configuration files described in
|
||||
<citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>. It operates
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -495,6 +500,30 @@
|
||||
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
|
||||
</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>
|
||||
<term><option>--sector-size=<replaceable>BYTES</replaceable></option></term>
|
||||
|
||||
|
||||
@ -206,7 +206,7 @@
|
||||
identify the main process of the service. The manager will proceed with starting follow-up units
|
||||
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
|
||||
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
|
||||
|
||||
60
meson.build
60
meson.build
@ -1247,53 +1247,30 @@ libcryptsetup = dependency('libcryptsetup',
|
||||
libcryptsetup_cflags = libcryptsetup.partial_dependency(includes: true, compile_args: true)
|
||||
|
||||
have = libcryptsetup.found()
|
||||
foreach ident : ['crypt_set_metadata_size',
|
||||
'crypt_activate_by_signed_key',
|
||||
'crypt_token_max',
|
||||
'crypt_reencrypt_init_by_passphrase',
|
||||
'crypt_reencrypt',
|
||||
'crypt_reencrypt_run',
|
||||
'crypt_set_data_offset',
|
||||
'crypt_set_keyring_to_link',
|
||||
'crypt_resume_by_volume_key',
|
||||
'crypt_token_set_external_path']
|
||||
conf.set10('HAVE_LIBCRYPTSETUP', have)
|
||||
|
||||
foreach ident : [
|
||||
'crypt_activate_by_token_pin', # 2.4
|
||||
'crypt_logf', # 2.4
|
||||
'crypt_reencrypt_run', # 2.4
|
||||
'crypt_token_external_path', # 2.4
|
||||
'crypt_token_max', # 2.4
|
||||
'crypt_set_keyring_to_link', # 2.7
|
||||
'crypt_token_set_external_path', # 2.7
|
||||
]
|
||||
|
||||
have_ident = have and cc.has_function(
|
||||
ident,
|
||||
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)
|
||||
conf.set10('HAVE_' + ident.to_upper(), have_ident)
|
||||
endforeach
|
||||
conf.set10('HAVE_LIBCRYPTSETUP', have)
|
||||
|
||||
if meson.version().version_compare('>=1.3.0')
|
||||
have = (cc.has_function(
|
||||
'crypt_activate_by_token_pin',
|
||||
prefix : '#include <libcryptsetup.h>',
|
||||
dependencies : libcryptsetup,
|
||||
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)
|
||||
conf.set10('HAVE_LIBCRYPTSETUP_PLUGINS',
|
||||
libcryptsetup_plugins.allowed() and
|
||||
conf.get('HAVE_CRYPT_ACTIVATE_BY_TOKEN_PIN') == 1 and
|
||||
conf.get('HAVE_CRYPT_LOGF') == 1 and
|
||||
conf.get('HAVE_CRYPT_TOKEN_EXTERNAL_PATH') == 1)
|
||||
|
||||
libcurl = dependency('libcurl',
|
||||
version : '>= 7.32.0',
|
||||
@ -1589,8 +1566,7 @@ conf.set10('ENABLE_IMPORTD', have)
|
||||
have = get_option('homed').require(
|
||||
conf.get('HAVE_OPENSSL') == 1 and
|
||||
conf.get('HAVE_LIBFDISK') == 1 and
|
||||
conf.get('HAVE_LIBCRYPTSETUP') == 1 and
|
||||
conf.get('HAVE_CRYPT_RESUME_BY_VOLUME_KEY') == 1,
|
||||
conf.get('HAVE_LIBCRYPTSETUP') == 1,
|
||||
error_message : 'openssl, fdisk and libcryptsetup required').allowed()
|
||||
conf.set10('ENABLE_HOMED', have)
|
||||
|
||||
|
||||
@ -14,3 +14,11 @@ ACTION!="remove", SUBSYSTEM=="block", \
|
||||
|
||||
# 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"
|
||||
|
||||
# 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"
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#include "bus-map-properties.h"
|
||||
#include "bus-unit-util.h"
|
||||
#include "bus-util.h"
|
||||
#include "capability-util.h"
|
||||
#include "copy.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
@ -135,7 +136,7 @@ static SecurityInfo *security_info_new(void) {
|
||||
|
||||
*info = (SecurityInfo) {
|
||||
.default_dependencies = true,
|
||||
.capability_bounding_set = UINT64_MAX,
|
||||
.capability_bounding_set = CAP_MASK_ALL,
|
||||
.restrict_namespaces = UINT64_MAX,
|
||||
._umask = 0002,
|
||||
};
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "capability-list.h"
|
||||
#include "capability-util.h"
|
||||
#include "errno-list.h"
|
||||
#include "extract-word.h"
|
||||
#include "locale-util.h"
|
||||
@ -809,3 +811,39 @@ bool nft_identifier_valid(const char *id) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -22,6 +22,8 @@ int parse_errno(const char *t);
|
||||
int parse_fd(const char *t);
|
||||
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_LEADING_ZERO (1U << 29)
|
||||
#define SAFE_ATO_REFUSE_LEADING_WHITESPACE (1U << 28)
|
||||
|
||||
@ -636,7 +636,7 @@ void exec_context_init(ExecContext *c) {
|
||||
.timer_slack_nsec = NSEC_INFINITY,
|
||||
.personality = PERSONALITY_INVALID,
|
||||
.timeout_clean_usec = USEC_INFINITY,
|
||||
.capability_bounding_set = CAP_MASK_UNSET,
|
||||
.capability_bounding_set = CAP_MASK_ALL,
|
||||
.restrict_namespaces = NAMESPACE_FLAGS_INITIAL,
|
||||
.delegate_namespaces = NAMESPACE_FLAGS_INITIAL,
|
||||
.log_level_max = -1,
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
#include "bpf-restrict-fs.h"
|
||||
#include "bus-error.h"
|
||||
#include "calendarspec.h"
|
||||
#include "capability-list.h"
|
||||
#include "capability-util.h"
|
||||
#include "cgroup-setup.h"
|
||||
#include "condition.h"
|
||||
@ -1873,41 +1872,22 @@ int config_parse_capability_set(
|
||||
void *userdata) {
|
||||
|
||||
uint64_t *capability_set = ASSERT_PTR(data);
|
||||
uint64_t sum = 0, initial, def;
|
||||
bool invert = false;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (rvalue[0] == '~') {
|
||||
invert = true;
|
||||
rvalue++;
|
||||
}
|
||||
uint64_t initial = streq(lvalue, "CapabilityBoundingSet") ? CAP_MASK_ALL : 0;
|
||||
|
||||
if (streq(lvalue, "CapabilityBoundingSet")) {
|
||||
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);
|
||||
r = parse_capability_set(rvalue, initial, capability_set);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s= specifier '%s', ignoring: %m", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sum == 0 || *capability_set == def)
|
||||
/* "", "~" or uninitialized data -> replace */
|
||||
*capability_set = invert ? ~sum : sum;
|
||||
else {
|
||||
/* previous data -> merge */
|
||||
if (invert)
|
||||
*capability_set &= ~sum;
|
||||
else
|
||||
*capability_set |= sum;
|
||||
}
|
||||
if (*capability_set == CAP_MASK_UNSET)
|
||||
*capability_set = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2768,7 +2768,7 @@ static void reset_arguments(void) {
|
||||
arg_default_environment = strv_free(arg_default_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_protect_system = -1;
|
||||
arg_timer_slack_nsec = NSEC_INFINITY;
|
||||
|
||||
@ -55,6 +55,13 @@ static inline int strcmp_ptr(const sd_char *a, const sd_char *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) {
|
||||
if (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;
|
||||
}
|
||||
|
||||
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) {
|
||||
return strcasecmp_ptr(a, b) == 0;
|
||||
}
|
||||
|
||||
@ -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_change_password = false;
|
||||
static ExportFormat arg_export_format = EXPORT_FORMAT_FULL;
|
||||
static uint64_t arg_capability_bounding_set = UINT64_MAX;
|
||||
static uint64_t arg_capability_ambient_set = UINT64_MAX;
|
||||
static uint64_t arg_capability_bounding_set = CAP_MASK_UNSET;
|
||||
static uint64_t arg_capability_ambient_set = CAP_MASK_UNSET;
|
||||
static char *arg_blob_dir = NULL;
|
||||
static bool arg_blob_clear = false;
|
||||
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_BOUNDING_SET: {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
bool subtract = false;
|
||||
uint64_t parsed, *which, updated;
|
||||
const char *p, *field;
|
||||
uint64_t *which;
|
||||
const char *field;
|
||||
|
||||
if (c == ARG_CAPABILITY_AMBIENT_SET) {
|
||||
which = &arg_capability_ambient_set;
|
||||
@ -4797,42 +4796,27 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*which = UINT64_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
p = optarg;
|
||||
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)
|
||||
if (capability_set_to_strv(*which, &l) < 0)
|
||||
return log_oom();
|
||||
|
||||
r = sd_json_variant_set_field_strv(match_identity ?: &arg_identity_extra, field, l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set %s field: %m", field);
|
||||
|
||||
*which = updated;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -1788,12 +1788,10 @@ static int luks_format(
|
||||
if (r < 0)
|
||||
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 */
|
||||
r = sym_crypt_set_metadata_size(cd, 4096U*1024U, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to change LUKS2 metadata size: %m");
|
||||
#endif
|
||||
|
||||
build_good_pbkdf(&good_pbkdf, hr);
|
||||
build_minimal_pbkdf(&minimal_pbkdf, hr);
|
||||
|
||||
@ -31,6 +31,11 @@ int json_dispatch_unhex_iovec(const char *name, sd_json_variant *variant, sd_jso
|
||||
size_t sz;
|
||||
int r;
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
iovec_done(iov);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_string(variant))
|
||||
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;
|
||||
int r;
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
iovec_done(iov);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_string(variant))
|
||||
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);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
iovec_done(iov);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_array(variant))
|
||||
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 = {};
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -5292,6 +5292,11 @@ _public_ int sd_json_dispatch_stdbool(const char *name, sd_json_variant *variant
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*b = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_boolean(variant))
|
||||
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(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*b = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_boolean(variant))
|
||||
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(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
|
||||
* implementations that cannot do 64bit integers. */
|
||||
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(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
|
||||
* 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
|
||||
@ -5377,6 +5397,11 @@ _public_ int sd_json_dispatch_uint32(const char *name, sd_json_variant *variant,
|
||||
assert_return(variant, -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);
|
||||
if (r < 0)
|
||||
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(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*i = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_int64(name, variant, flags, &i64);
|
||||
if (r < 0)
|
||||
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(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*i = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_int64(name, variant, flags, &i64);
|
||||
if (r < 0)
|
||||
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(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*u = UINT16_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_uint64(name, variant, flags, &u64);
|
||||
if (r < 0)
|
||||
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(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*i = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_int64(name, variant, flags, &i64);
|
||||
if (r < 0)
|
||||
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(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*u = UINT8_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_uint64(name, variant, flags, &u64);
|
||||
if (r < 0)
|
||||
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(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 */
|
||||
if (sd_json_variant_is_string(variant) && safe_atod(sd_json_variant_string(variant), d) >= 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(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*s = mfree(*s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_const_string(name, variant, flags, &n);
|
||||
if (r < 0)
|
||||
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) {
|
||||
uid_t *uid = userdata;
|
||||
uint64_t k;
|
||||
uint32_t k;
|
||||
int r;
|
||||
|
||||
assert_return(variant, -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;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_unsigned(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
|
||||
|
||||
k = sd_json_variant_unsigned(variant);
|
||||
if (k > UINT32_MAX || !uid_is_valid(k))
|
||||
r = sd_json_dispatch_uint32(name, variant, flags, &k);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!uid_is_valid(k))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid UID/GID.", strna(name));
|
||||
|
||||
*uid = k;
|
||||
@ -5678,12 +5738,18 @@ _public_ int sd_json_dispatch_signal(const char *name, sd_json_variant *variant,
|
||||
}
|
||||
|
||||
int k;
|
||||
r = sd_json_dispatch_int(name, variant, flags, &k);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (sd_json_variant_is_string(variant)) {
|
||||
k = signal_from_string(sd_json_variant_string(variant));
|
||||
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))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid signal.", strna(name));
|
||||
if (!SIGNAL_VALID(k))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid signal.", strna(name));
|
||||
}
|
||||
|
||||
*signo = k;
|
||||
return 0;
|
||||
|
||||
@ -2421,6 +2421,15 @@ _public_ int sd_varlink_collect_full(
|
||||
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));
|
||||
|
||||
_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);
|
||||
if (r < 0)
|
||||
return varlink_log_errno(v, r, "Failed to append JSON object to array: %m");
|
||||
|
||||
@ -96,7 +96,7 @@ static int parse_caps(
|
||||
if (!caps)
|
||||
continue;
|
||||
|
||||
if (*caps == UINT64_MAX)
|
||||
if (*caps == CAP_MASK_UNSET)
|
||||
b = subtract ? all_capabilities() : 0;
|
||||
else
|
||||
b = *caps;
|
||||
@ -764,14 +764,14 @@ static int apply_user_record_settings(
|
||||
|
||||
uint64_t a, b;
|
||||
a = user_record_capability_ambient_set(ur);
|
||||
if (a == UINT64_MAX)
|
||||
if (a == CAP_MASK_UNSET)
|
||||
a = default_capability_ambient_set;
|
||||
|
||||
b = user_record_capability_bounding_set(ur);
|
||||
if (b == UINT64_MAX)
|
||||
if (b == CAP_MASK_UNSET)
|
||||
b = default_capability_bounding_set;
|
||||
|
||||
if (a != UINT64_MAX && a != 0) {
|
||||
if (a != CAP_MASK_UNSET && a != 0) {
|
||||
a &= b;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
pam_syslog_errno(handle, LOG_ERR, r,
|
||||
@ -802,7 +802,7 @@ static uint64_t pick_default_capability_ambient_set(
|
||||
|
||||
return ur &&
|
||||
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 {
|
||||
@ -1735,7 +1735,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
|
||||
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;
|
||||
bool debug = false;
|
||||
if (parse_argv(handle,
|
||||
@ -1800,7 +1800,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
if (r != PAM_SUCCESS)
|
||||
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);
|
||||
|
||||
r = apply_user_record_settings(handle, ur, debug, default_capability_bounding_set, default_capability_ambient_set);
|
||||
|
||||
@ -324,7 +324,7 @@ static int oci_capabilities(const char *name, sd_json_variant *v, sd_json_dispat
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (s->full_capabilities.bounding != UINT64_MAX) {
|
||||
if (s->full_capabilities.bounding != CAP_MASK_UNSET) {
|
||||
s->capability = s->full_capabilities.bounding;
|
||||
s->drop_capability = ~s->full_capabilities.bounding;
|
||||
}
|
||||
|
||||
@ -1694,7 +1694,7 @@ static int verify_arguments(void) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --port= without private networking.");
|
||||
|
||||
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.");
|
||||
|
||||
if ((arg_caps_ambient & arg_caps_retain) != arg_caps_ambient)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1015,14 +1015,12 @@ static int verb_service(int argc, char **argv, void *userdata) {
|
||||
}
|
||||
|
||||
static int resolve_openpgp(sd_bus *bus, const char *address) {
|
||||
const char *domain, *full;
|
||||
int r;
|
||||
_cleanup_free_ char *hashed = NULL;
|
||||
|
||||
assert(bus);
|
||||
assert(address);
|
||||
|
||||
domain = strrchr(address, '@');
|
||||
const char *domain = strrchr(address, '@');
|
||||
if (!domain)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"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);
|
||||
domain++;
|
||||
|
||||
_cleanup_free_ char *hashed = NULL;
|
||||
r = string_hashsum_sha256(address, domain - 1 - address, &hashed);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Hashing failed: %m");
|
||||
|
||||
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);
|
||||
|
||||
r = resolve_record(bus, full,
|
||||
arg_class ?: DNS_CLASS_IN,
|
||||
arg_type ?: DNS_TYPE_OPENPGPKEY, false);
|
||||
r = resolve_record(
|
||||
bus,
|
||||
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);
|
||||
r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Hashing failed: %m");
|
||||
hashed = mfree(hashed);
|
||||
r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Hashing failed: %m");
|
||||
|
||||
full = strjoina(hashed, "._openpgpkey.", domain);
|
||||
log_debug("Looking up \"%s\".", full);
|
||||
full = mfree(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,
|
||||
arg_class ?: DNS_CLASS_IN,
|
||||
arg_type ?: DNS_TYPE_OPENPGPKEY, true);
|
||||
}
|
||||
|
||||
return r;
|
||||
return resolve_record(
|
||||
bus,
|
||||
full,
|
||||
arg_class ?: DNS_CLASS_IN,
|
||||
arg_type ?: DNS_TYPE_OPENPGPKEY,
|
||||
/* warn_missing= */ true);
|
||||
}
|
||||
|
||||
static int verb_openpgp(int argc, char **argv, void *userdata) {
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#include "blockdev-util.h"
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
|
||||
@ -16,6 +18,9 @@ void block_device_done(BlockDevice *d) {
|
||||
|
||||
d->node = mfree(d->node);
|
||||
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) {
|
||||
@ -26,6 +31,61 @@ void block_device_array_free(BlockDevice *d, size_t n_devices) {
|
||||
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) {
|
||||
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
|
||||
int r;
|
||||
@ -65,7 +125,7 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
|
||||
|
||||
r = sd_device_get_devname(dev, &node);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -74,7 +134,7 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
|
||||
|
||||
r = sd_device_get_devnum(dev, &devno);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -85,7 +145,7 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
|
||||
if (FLAGS_SET(flags, BLOCKDEV_LIST_IGNORE_ZRAM)) {
|
||||
r = device_sysname_startswith(dev, "zram");
|
||||
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;
|
||||
}
|
||||
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)) {
|
||||
r = blockdev_partscan_enabled(dev);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t size = UINT64_MAX;
|
||||
if (FLAGS_SET(flags, BLOCKDEV_LIST_IGNORE_EMPTY) || ret_devices) {
|
||||
|
||||
r = device_get_sysattr_u64(dev, "size", &size);
|
||||
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
|
||||
/* 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 */
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -129,11 +188,18 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
|
||||
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) {
|
||||
uint64_t diskseq = UINT64_MAX;
|
||||
r = sd_device_get_diskseq(dev, &diskseq);
|
||||
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))
|
||||
return log_oom();
|
||||
@ -147,6 +213,9 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re
|
||||
.symlinks = TAKE_PTR(list),
|
||||
.diskseq = diskseq,
|
||||
.size = size,
|
||||
.model = TAKE_PTR(model),
|
||||
.vendor = TAKE_PTR(vendor),
|
||||
.subsystem = TAKE_PTR(subsystem),
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
@ -10,11 +10,15 @@ typedef enum BlockDevListFlags {
|
||||
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_EMPTY = 1 << 5, /* Ignore disks of zero size (usually drives without a medium) */
|
||||
BLOCKDEV_LIST_METADATA = 1 << 6, /* Fill in model, vendor, subsystem */
|
||||
} BlockDevListFlags;
|
||||
|
||||
typedef struct BlockDevice {
|
||||
char *node;
|
||||
char **symlinks;
|
||||
char *model;
|
||||
char *vendor;
|
||||
char *subsystem;
|
||||
uint64_t diskseq;
|
||||
uint64_t size; /* in bytes */
|
||||
} BlockDevice;
|
||||
|
||||
@ -16,9 +16,7 @@
|
||||
static void *cryptsetup_dl = NULL;
|
||||
|
||||
DLSYM_PROTOTYPE(crypt_activate_by_passphrase) = NULL;
|
||||
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||
DLSYM_PROTOTYPE(crypt_activate_by_signed_key) = NULL;
|
||||
#endif
|
||||
DLSYM_PROTOTYPE(crypt_activate_by_volume_key) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_deactivate_by_name) = 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_verity_info) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_get_volume_key_size) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_header_restore) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_init) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_init_by_name) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_keyslot_add_by_volume_key) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_keyslot_destroy) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_keyslot_max) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_load) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_resize) = NULL;
|
||||
#if HAVE_CRYPT_RESUME_BY_VOLUME_KEY
|
||||
DLSYM_PROTOTYPE(crypt_resume_by_volume_key) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_metadata_locking) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_reencrypt_init_by_passphrase) = NULL;
|
||||
#if HAVE_CRYPT_REENCRYPT_RUN
|
||||
DLSYM_PROTOTYPE(crypt_reencrypt_run);
|
||||
#else
|
||||
DLSYM_PROTOTYPE(crypt_reencrypt);
|
||||
#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_offset) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_set_debug_level) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_set_log_callback) = NULL;
|
||||
#if HAVE_CRYPT_SET_METADATA_SIZE
|
||||
DLSYM_PROTOTYPE(crypt_set_metadata_size) = NULL;
|
||||
#endif
|
||||
DLSYM_PROTOTYPE(crypt_set_pbkdf_type) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_suspend) = NULL;
|
||||
DLSYM_PROTOTYPE(crypt_token_json_get) = NULL;
|
||||
@ -66,19 +69,6 @@ DLSYM_PROTOTYPE(crypt_token_set_external_path) = NULL;
|
||||
#endif
|
||||
DLSYM_PROTOTYPE(crypt_token_status) = 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;
|
||||
|
||||
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(
|
||||
&cryptsetup_dl, "libcryptsetup.so.12", LOG_DEBUG,
|
||||
DLSYM_ARG(crypt_activate_by_passphrase),
|
||||
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||
DLSYM_ARG(crypt_activate_by_signed_key),
|
||||
#endif
|
||||
DLSYM_ARG(crypt_activate_by_volume_key),
|
||||
DLSYM_ARG(crypt_deactivate_by_name),
|
||||
DLSYM_ARG(crypt_format),
|
||||
@ -253,22 +241,27 @@ int dlopen_cryptsetup(void) {
|
||||
DLSYM_ARG(crypt_get_uuid),
|
||||
DLSYM_ARG(crypt_get_verity_info),
|
||||
DLSYM_ARG(crypt_get_volume_key_size),
|
||||
DLSYM_ARG(crypt_header_restore),
|
||||
DLSYM_ARG(crypt_init),
|
||||
DLSYM_ARG(crypt_init_by_name),
|
||||
DLSYM_ARG(crypt_keyslot_add_by_volume_key),
|
||||
DLSYM_ARG(crypt_keyslot_destroy),
|
||||
DLSYM_ARG(crypt_keyslot_max),
|
||||
DLSYM_ARG(crypt_load),
|
||||
DLSYM_ARG(crypt_resize),
|
||||
#if HAVE_CRYPT_RESUME_BY_VOLUME_KEY
|
||||
DLSYM_ARG(crypt_resume_by_volume_key),
|
||||
DLSYM_ARG(crypt_metadata_locking),
|
||||
DLSYM_ARG(crypt_reencrypt_init_by_passphrase),
|
||||
#if HAVE_CRYPT_REENCRYPT_RUN
|
||||
DLSYM_ARG(crypt_reencrypt_run),
|
||||
#else
|
||||
DLSYM_ARG(crypt_reencrypt),
|
||||
#endif
|
||||
DLSYM_ARG(crypt_resize),
|
||||
DLSYM_ARG(crypt_resume_by_volume_key),
|
||||
DLSYM_ARG(crypt_set_data_device),
|
||||
DLSYM_ARG(crypt_set_data_offset),
|
||||
DLSYM_ARG(crypt_set_debug_level),
|
||||
DLSYM_ARG(crypt_set_log_callback),
|
||||
#if HAVE_CRYPT_SET_METADATA_SIZE
|
||||
DLSYM_ARG(crypt_set_metadata_size),
|
||||
#endif
|
||||
DLSYM_ARG(crypt_set_pbkdf_type),
|
||||
DLSYM_ARG(crypt_suspend),
|
||||
DLSYM_ARG(crypt_token_json_get),
|
||||
@ -281,19 +274,6 @@ int dlopen_cryptsetup(void) {
|
||||
#endif
|
||||
DLSYM_ARG(crypt_token_status),
|
||||
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));
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
@ -16,9 +16,7 @@
|
||||
#endif
|
||||
|
||||
extern DLSYM_PROTOTYPE(crypt_activate_by_passphrase);
|
||||
#if HAVE_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_deactivate_by_name);
|
||||
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_verity_info);
|
||||
extern DLSYM_PROTOTYPE(crypt_get_volume_key_size);
|
||||
extern DLSYM_PROTOTYPE(crypt_header_restore);
|
||||
extern DLSYM_PROTOTYPE(crypt_init);
|
||||
extern DLSYM_PROTOTYPE(crypt_init_by_name);
|
||||
extern DLSYM_PROTOTYPE(crypt_keyslot_add_by_volume_key);
|
||||
extern DLSYM_PROTOTYPE(crypt_keyslot_destroy);
|
||||
extern DLSYM_PROTOTYPE(crypt_keyslot_max);
|
||||
extern DLSYM_PROTOTYPE(crypt_load);
|
||||
extern DLSYM_PROTOTYPE(crypt_resize);
|
||||
#if HAVE_CRYPT_RESUME_BY_VOLUME_KEY
|
||||
extern DLSYM_PROTOTYPE(crypt_resume_by_volume_key);
|
||||
extern DLSYM_PROTOTYPE(crypt_metadata_locking);
|
||||
extern DLSYM_PROTOTYPE(crypt_reencrypt_init_by_passphrase);
|
||||
#if HAVE_CRYPT_REENCRYPT_RUN
|
||||
extern DLSYM_PROTOTYPE(crypt_reencrypt_run);
|
||||
#else
|
||||
extern DLSYM_PROTOTYPE(crypt_reencrypt);
|
||||
#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_offset);
|
||||
extern DLSYM_PROTOTYPE(crypt_set_debug_level);
|
||||
extern DLSYM_PROTOTYPE(crypt_set_log_callback);
|
||||
#if HAVE_CRYPT_SET_METADATA_SIZE
|
||||
extern DLSYM_PROTOTYPE(crypt_set_metadata_size);
|
||||
#endif
|
||||
extern DLSYM_PROTOTYPE(crypt_set_pbkdf_type);
|
||||
extern DLSYM_PROTOTYPE(crypt_suspend);
|
||||
extern DLSYM_PROTOTYPE(crypt_token_json_get);
|
||||
@ -64,19 +67,6 @@ extern DLSYM_PROTOTYPE(crypt_token_set_external_path);
|
||||
#endif
|
||||
extern DLSYM_PROTOTYPE(crypt_token_status);
|
||||
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);
|
||||
|
||||
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_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
|
||||
|
||||
int dlopen_cryptsetup(void);
|
||||
|
||||
@ -2668,13 +2668,11 @@ static int verity_can_reuse(
|
||||
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.");
|
||||
|
||||
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||
/* 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
|
||||
* signing for the new one, and vice versa. */
|
||||
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.");
|
||||
#endif
|
||||
|
||||
*ret_cd = TAKE_PTR(cd);
|
||||
return 0;
|
||||
@ -2820,7 +2818,6 @@ static int do_crypt_activate_verity(
|
||||
check_signature = false;
|
||||
|
||||
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. */
|
||||
r = sym_crypt_activate_by_signed_key(
|
||||
cd,
|
||||
@ -2842,11 +2839,6 @@ static int do_crypt_activate_verity(
|
||||
* -ENOKEY, which means "password required, but I have none". */
|
||||
if (r == -ENOKEY)
|
||||
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
|
||||
* works we'll try to activate without telling the kernel the signature. */
|
||||
|
||||
@ -390,6 +390,19 @@ _noreturn_ void log_test_failed_internal(const char *file, int line, const char
|
||||
})
|
||||
#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__
|
||||
# define ASSERT_PTR_EQ(expr1, expr2) __coverity_check__((expr1) == (expr2))
|
||||
#else
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "capability-list.h"
|
||||
#include "capability-util.h"
|
||||
#include "format-util.h"
|
||||
#include "glyph-util.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));
|
||||
|
||||
uint64_t caps = user_record_capability_bounding_set(hr);
|
||||
if (caps != UINT64_MAX) {
|
||||
if (caps != CAP_MASK_UNSET) {
|
||||
_cleanup_free_ char *scaps = NULL;
|
||||
|
||||
(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);
|
||||
if (caps != UINT64_MAX) {
|
||||
if (caps != CAP_MASK_UNSET) {
|
||||
_cleanup_free_ char *scaps = NULL;
|
||||
|
||||
(void) capability_set_to_string(caps, &scaps);
|
||||
|
||||
@ -4,27 +4,119 @@
|
||||
|
||||
#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(
|
||||
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_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_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_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_DEFINE_OUTPUT(diskseq, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
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(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(
|
||||
io_systemd_Repart,
|
||||
"io.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."),
|
||||
&vl_method_ListCandidateDevices,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Not a single candidate block device could be found."),
|
||||
|
||||
@ -44,7 +44,7 @@ int verb_add_dependency(int argc, char *argv[], void *userdata) {
|
||||
else
|
||||
assert_not_reached();
|
||||
|
||||
if (install_client_side()) {
|
||||
if (install_client_side() != INSTALL_CLIENT_SIDE_NO) {
|
||||
InstallChange *changes = NULL;
|
||||
size_t n_changes = 0;
|
||||
|
||||
|
||||
@ -370,7 +370,8 @@ int verb_edit(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -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 (strv_isempty(names)) {
|
||||
if (arg_no_reload || install_client_side())
|
||||
if (arg_no_reload || install_client_side() != INSTALL_CLIENT_SIDE_NO)
|
||||
return 0;
|
||||
|
||||
r = daemon_reload(ACTION_RELOAD, /* graceful= */ false);
|
||||
@ -119,41 +119,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (install_client_side()) {
|
||||
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 {
|
||||
if (install_client_side() == INSTALL_CLIENT_SIDE_NO) {
|
||||
_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;
|
||||
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)
|
||||
STRV_FOREACH(unit, names)
|
||||
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)
|
||||
@ -334,7 +334,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
if (arg_now) {
|
||||
_cleanup_strv_free_ char **new_args = NULL;
|
||||
const char *start_verb;
|
||||
bool accept_path, prohibit_templates;
|
||||
bool accept_path, prohibit_templates, dead_ok = false;
|
||||
|
||||
if (streq(verb, "enable")) {
|
||||
start_verb = "start";
|
||||
@ -344,6 +344,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
start_verb = "stop";
|
||||
accept_path = false;
|
||||
prohibit_templates = false;
|
||||
dead_ok = true; /* If the service is not running anyway, no need to stop it. */
|
||||
} else if (streq(verb, "reenable")) {
|
||||
/* Note that we use try-restart here. This matches the semantics of reenable better,
|
||||
* 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),
|
||||
"--now can only be used with verb enable, disable, reenable, or mask.");
|
||||
|
||||
if (install_client_side())
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE),
|
||||
"--now cannot be used when systemd is not running or in conjunction with --root=/--global, refusing.");
|
||||
switch (install_client_side()) {
|
||||
case INSTALL_CLIENT_SIDE_NO:
|
||||
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);
|
||||
|
||||
|
||||
@ -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 */
|
||||
enabled = r == SYSV_UNIT_ENABLED;
|
||||
|
||||
if (install_client_side())
|
||||
if (install_client_side() != INSTALL_CLIENT_SIDE_NO)
|
||||
STRV_FOREACH(name, names) {
|
||||
UnitFileState state;
|
||||
|
||||
|
||||
@ -180,7 +180,7 @@ int verb_list_unit_files(int argc, char *argv[], void *userdata) {
|
||||
unsigned c = 0;
|
||||
int r;
|
||||
|
||||
if (install_client_side()) {
|
||||
if (install_client_side() != INSTALL_CLIENT_SIDE_NO) {
|
||||
unsigned n_units;
|
||||
|
||||
r = unit_file_get_list(arg_runtime_scope, arg_root, arg_states, strv_skip(argv, 1), &h);
|
||||
|
||||
@ -19,7 +19,7 @@ int verb_preset_all(int argc, char *argv[], void *userdata) {
|
||||
if (should_bypass("SYSTEMD_PRESET"))
|
||||
return 0;
|
||||
|
||||
if (install_client_side()) {
|
||||
if (install_client_side() != INSTALL_CLIENT_SIDE_NO) {
|
||||
InstallChange *changes = NULL;
|
||||
size_t n_changes = 0;
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ static void emit_cmdline_warning(void) {
|
||||
static int determine_default(char **ret_name) {
|
||||
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);
|
||||
if (r == -ERFKILL)
|
||||
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)
|
||||
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;
|
||||
size_t n_changes = 0;
|
||||
|
||||
|
||||
@ -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 */
|
||||
if (!force_client_side &&
|
||||
!install_client_side() &&
|
||||
install_client_side() == INSTALL_CLIENT_SIDE_NO &&
|
||||
!unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_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;
|
||||
}
|
||||
|
||||
bool install_client_side(void) {
|
||||
/* Decides when to execute enable/disable/... operations client-side 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;
|
||||
InstallClientSide install_client_side(void) {
|
||||
/* Decides whether to execute enable/disable/… client-side offline operation rather than
|
||||
* server-side. */
|
||||
|
||||
/* Unsupported environment variable, mostly for debugging purposes */
|
||||
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) {
|
||||
|
||||
@ -69,7 +69,16 @@ int unit_get_dependencies(sd_bus *bus, const char *name, char ***ret);
|
||||
const char* unit_type_suffix(const char *unit);
|
||||
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);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@
|
||||
#include <math.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "capability-util.h"
|
||||
#include "locale-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "tests.h"
|
||||
@ -888,4 +889,127 @@ TEST(nft_identifier_valid) {
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
ASSERT_EQ(current, all_capabilities());
|
||||
|
||||
/* Sequential calls - testing merge behavior */
|
||||
current = CAP_MASK_UNSET;
|
||||
ASSERT_OK(parse_capability_set("cap_chown", CAP_MASK_UNSET, ¤t));
|
||||
ASSERT_EQ(current, make_cap(CAP_CHOWN));
|
||||
ASSERT_OK(parse_capability_set("cap_setuid", CAP_MASK_UNSET, ¤t));
|
||||
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, ¤t));
|
||||
ASSERT_OK(parse_capability_set("~cap_setuid", CAP_MASK_UNSET, ¤t));
|
||||
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, ¤t));
|
||||
ASSERT_EQ(current, make_cap(0));
|
||||
|
||||
current = CAP_MASK_UNSET;
|
||||
ASSERT_OK(parse_capability_set("5", CAP_MASK_UNSET, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
ASSERT_EQ(current, make_cap(CAP_CHOWN));
|
||||
|
||||
current = CAP_MASK_UNSET;
|
||||
ASSERT_OK(parse_capability_set("CaP_ChOwN", CAP_MASK_UNSET, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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, ¤t));
|
||||
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), ¤t));
|
||||
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, ¤t));
|
||||
ASSERT_EQ(current, make_cap(CAP_CHOWN) | make_cap(CAP_SETGID)); /* Merge because current != initial */
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
|
||||
@ -101,10 +101,6 @@ static int parse_roothashsig_option(const char *option, bool strict) {
|
||||
else
|
||||
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);
|
||||
arg_root_hash_signature_size = rhss;
|
||||
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");
|
||||
|
||||
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);
|
||||
if (r < 0) {
|
||||
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);
|
||||
}
|
||||
#else
|
||||
assert_not_reached();
|
||||
#endif
|
||||
} else
|
||||
r = crypt_activate_by_volume_key(cd, volume, rh, rh_size, arg_activate_flags);
|
||||
if (r < 0)
|
||||
|
||||
@ -78,6 +78,17 @@ fi
|
||||
systemd-dissect --umount "$IMAGE_DIR/mount"
|
||||
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=
|
||||
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)
|
||||
|
||||
@ -141,6 +141,12 @@ SizeMaxBytes=64M
|
||||
PaddingMinBytes=92M
|
||||
EOF
|
||||
|
||||
systemd-repart --definitions="$defs" \
|
||||
--dry-run=yes \
|
||||
--seed="$seed" \
|
||||
--include-partitions=home,swap \
|
||||
"-"
|
||||
|
||||
systemd-repart --offline="$OFFLINE" \
|
||||
--definitions="$defs" \
|
||||
--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}'
|
||||
}
|
||||
|
||||
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"
|
||||
run_testcases
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user