mirror of
https://github.com/systemd/systemd
synced 2026-02-25 16:54:44 +01:00
Compare commits
29 Commits
a2a78602b0
...
61b31f7999
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61b31f7999 | ||
|
|
ab83c7489d | ||
|
|
868fdc5520 | ||
|
|
8b5374d6c2 | ||
|
|
7537717aed | ||
|
|
b0ca987cd9 | ||
|
|
a5ff474a2b | ||
|
|
f0b2ea63f4 | ||
|
|
d39b103719 | ||
|
|
f29edb227c | ||
|
|
a51e5bd1f1 | ||
|
|
54b745d7bb | ||
|
|
d8302c2fd9 | ||
|
|
bd994b2f81 | ||
|
|
9d193c8f13 | ||
|
|
ffe69b3fa1 | ||
|
|
fd0b6187be | ||
|
|
4ed5e84bea | ||
|
|
eaeceb5fb6 | ||
|
|
2afe8e28f8 | ||
|
|
2619656950 | ||
|
|
5c247bbd57 | ||
|
|
c71aa4047b | ||
|
|
aaadf3e907 | ||
|
|
e0a2369dd1 | ||
|
|
fc03d200c7 | ||
|
|
1c867dc71a | ||
|
|
b65467b647 | ||
|
|
dc3e59f50c |
9
NEWS
9
NEWS
@ -55,7 +55,14 @@ CHANGES WITH 260 in spe:
|
|||||||
|
|
||||||
Device nodes should not be owned by a non-system user/group. It is
|
Device nodes should not be owned by a non-system user/group. It is
|
||||||
recommended to check udev rules files with 'udevadm verify' and/or
|
recommended to check udev rules files with 'udevadm verify' and/or
|
||||||
'udevadm test' commands .
|
'udevadm test' commands.
|
||||||
|
|
||||||
|
* systemd-repart will now make use of mkfs.xfs's support for
|
||||||
|
populating XFS filesystems from a directory. This support was
|
||||||
|
added in xfsprogs 6.17.0 released 20 October 2025. As there is no
|
||||||
|
proper way to detect whether mkfs.xfs supports populating from a
|
||||||
|
directory or not, we make use of it unconditionally and have dropped
|
||||||
|
support for the old way using protofiles.
|
||||||
|
|
||||||
New system interfaces and components:
|
New system interfaces and components:
|
||||||
|
|
||||||
|
|||||||
1
TODO
1
TODO
@ -967,7 +967,6 @@ Features:
|
|||||||
|
|
||||||
* Varlinkification of the following command line tools, to open them up to
|
* Varlinkification of the following command line tools, to open them up to
|
||||||
other programs via IPC:
|
other programs via IPC:
|
||||||
- bootctl
|
|
||||||
- coredumpcl
|
- coredumpcl
|
||||||
- systemd-bless-boot
|
- systemd-bless-boot
|
||||||
- systemd-measure
|
- systemd-measure
|
||||||
|
|||||||
@ -120,7 +120,12 @@ node /org/freedesktop/sysupdate1/target/host {
|
|||||||
in t flags,
|
in t flags,
|
||||||
out s json);
|
out s json);
|
||||||
CheckNew(out s new_version);
|
CheckNew(out s new_version);
|
||||||
Update(in s new_version,
|
Acquire(in s new_version,
|
||||||
|
in t flags,
|
||||||
|
out s new_version,
|
||||||
|
out t job_id,
|
||||||
|
out o job_path);
|
||||||
|
Install(in s new_version,
|
||||||
in t flags,
|
in t flags,
|
||||||
out s new_version,
|
out s new_version,
|
||||||
out t job_id,
|
out t job_id,
|
||||||
@ -163,7 +168,9 @@ node /org/freedesktop/sysupdate1/target/host {
|
|||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="CheckNew()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="CheckNew()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="Update()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="Acquire()"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-method" generated="True" extra-ref="Install()"/>
|
||||||
|
|
||||||
<variablelist class="dbus-method" generated="True" extra-ref="Vacuum()"/>
|
<variablelist class="dbus-method" generated="True" extra-ref="Vacuum()"/>
|
||||||
|
|
||||||
@ -245,7 +252,8 @@ node /org/freedesktop/sysupdate1/target/host {
|
|||||||
<listitem><para>A boolean indicating whether this version is incomplete, which means that it is
|
<listitem><para>A boolean indicating whether this version is incomplete, which means that it is
|
||||||
missing some file. Note that only installed incomplete versions will be offered by the service;
|
missing some file. Note that only installed incomplete versions will be offered by the service;
|
||||||
versions that are incomplete on the server-side are completely ignored. Incomplete versions can
|
versions that are incomplete on the server-side are completely ignored. Incomplete versions can
|
||||||
be repaired in-place by calling <function>Update()</function> on that version.</para></listitem>
|
be repaired in-place by calling <function>Acquire()</function> and <function>Install()</function>
|
||||||
|
on that version.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
@ -261,16 +269,25 @@ node /org/freedesktop/sysupdate1/target/host {
|
|||||||
<function>Describe()</function> to query more information about the version returned by this method.
|
<function>Describe()</function> to query more information about the version returned by this method.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para><function>Update()</function> installs an update for this target. If a
|
<para><function>Acquire()</function> downloads an update for this target, if one is available. If a
|
||||||
<varname>new_version</varname> is specified, that is the version that gets installed. Otherwise, the
|
<varname>new_version</varname> is specified, that is the version that gets downloaded. Otherwise, the
|
||||||
latest version is installed. The <varname>flags</varname> argument is added for future
|
latest version is downloaded. Call <function>Install()</function> to install the acquired update.
|
||||||
extensibility. No flags are currently defined, and the argument is required to be set to
|
The <varname>flags</varname> argument is added for future extensibility. No flags are currently
|
||||||
<literal>0</literal>. Unlike all the other methods in this interface, <function>Update()</function>
|
defined, and the argument is required to be set to <literal>0</literal>. This method pulls both
|
||||||
does not wait for its job to complete. Instead, it returns the job's numeric ID and object path as soon
|
metadata and payload data from the network.</para>
|
||||||
as the job begins, so that the caller can listen for progress updates or cancel the operation. This
|
|
||||||
method also returns the version the target will be updated to, for cases where no version was specified
|
<para><function>Install()</function> installs an already-acquired update for this target. If a
|
||||||
by the caller. This method pulls both metadata and payload data from the network. Listen for the
|
<varname>new_version</varname> is specified, that is the version that gets installed, assuming it has
|
||||||
Manager's <function>JobRemoved()</function> signal to detect when the job is complete.</para>
|
already been acquired. Otherwise, the latest acquired version is installed. The
|
||||||
|
<varname>flags</varname> argument is added for future extensibility. No flags are currently defined,
|
||||||
|
and the argument is required to be set to <literal>0</literal>.</para>
|
||||||
|
|
||||||
|
<para>Unlike all the other methods in this interface, <function>Acquire()</function> and
|
||||||
|
<function>Install()</function> do not wait for their jobs to complete. Instead, they return the job's
|
||||||
|
numeric ID and object path as soon as the job begins, so that the caller can listen for progress
|
||||||
|
updates or cancel the operation. These methods also return the version the target will be updated to,
|
||||||
|
for cases where no version was specified by the caller. Listen for the Manager's
|
||||||
|
<function>JobRemoved()</function> signal to detect when the job is complete.</para>
|
||||||
|
|
||||||
<para><function>Vacuum()</function> deletes old installed versions of this target to free up space.
|
<para><function>Vacuum()</function> deletes old installed versions of this target to free up space.
|
||||||
It returns the number of instances that have been deleted.</para>
|
It returns the number of instances that have been deleted.</para>
|
||||||
@ -347,7 +364,7 @@ node /org/freedesktop/sysupdate1/target/host {
|
|||||||
preemptive decisions to be made about features that are planned to appear in future releases of the OS.
|
preemptive decisions to be made about features that are planned to appear in future releases of the OS.
|
||||||
The drop-in will have a filename of <literal>50-systemd-sysupdate-enabled.conf</literal>.
|
The drop-in will have a filename of <literal>50-systemd-sysupdate-enabled.conf</literal>.
|
||||||
This method only changes configuration files; to actually apply the changes, clients will need to
|
This method only changes configuration files; to actually apply the changes, clients will need to
|
||||||
call <function>Update()</function>.
|
call <function>Acquire()</function> and <function>Install()</function>.
|
||||||
Depending on the exact needs of the client, it can choose to update the system to the latest available
|
Depending on the exact needs of the client, it can choose to update the system to the latest available
|
||||||
version, or it can extend the newest existing installation in-place (by passing in the version returned
|
version, or it can extend the newest existing installation in-place (by passing in the version returned
|
||||||
by <varname>GetVersion()</varname>).
|
by <varname>GetVersion()</varname>).
|
||||||
@ -397,7 +414,8 @@ node /org/freedesktop/sysupdate1/target/host {
|
|||||||
use the polkit action <interfacename>org.freedesktop.sysupdate1.check</interfacename>.
|
use the polkit action <interfacename>org.freedesktop.sysupdate1.check</interfacename>.
|
||||||
By default, this action is permitted without administrator authentication.</para>
|
By default, this action is permitted without administrator authentication.</para>
|
||||||
|
|
||||||
<para><function>Update()</function> uses the polkit action
|
<para><function>Acquire()</function> and <function>Install()</function>
|
||||||
|
use the polkit action
|
||||||
<interfacename>org.freedesktop.sysupdate1.update</interfacename> when no version is specified.
|
<interfacename>org.freedesktop.sysupdate1.update</interfacename> when no version is specified.
|
||||||
By default, this action is permitted without administrator authentication. When a version is
|
By default, this action is permitted without administrator authentication. When a version is
|
||||||
specified, <interfacename>org.freedesktop.sysupdate1.update-to-version</interfacename> is
|
specified, <interfacename>org.freedesktop.sysupdate1.update-to-version</interfacename> is
|
||||||
@ -496,14 +514,15 @@ node /org/freedesktop/sysupdate1/job/_1 {
|
|||||||
|
|
||||||
<para>The <varname>Type</varname> property exposes the type of operation (one of:
|
<para>The <varname>Type</varname> property exposes the type of operation (one of:
|
||||||
<literal>list</literal>, <literal>describe</literal>, <literal>check-new</literal>,
|
<literal>list</literal>, <literal>describe</literal>, <literal>check-new</literal>,
|
||||||
<literal>update</literal>, <literal>vacuum</literal>, or <literal>describe-feature</literal>).</para>
|
<literal>acquire</literal>, <literal>install</literal>, <literal>vacuum</literal>, or
|
||||||
|
<literal>describe-feature</literal>).</para>
|
||||||
|
|
||||||
<para>The <varname>Offline</varname> property exposes whether the job is permitted to access
|
<para>The <varname>Offline</varname> property exposes whether the job is permitted to access
|
||||||
the network or not.</para>
|
the network or not.</para>
|
||||||
|
|
||||||
<para>The <varname>Progress</varname> property exposes the current progress of the job as a value
|
<para>The <varname>Progress</varname> property exposes the current progress of the job as a value
|
||||||
between 0 and 100. It is only available for <literal>update</literal> jobs; for all other jobs
|
between 0 and 100. It is only available for <literal>acquire</literal> and <literal>install</literal>
|
||||||
it is always 0.</para>
|
jobs; for all other jobs it is always 0.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
@ -562,7 +581,8 @@ node /org/freedesktop/sysupdate1/job/_1 {
|
|||||||
<para><function>List()</function>,
|
<para><function>List()</function>,
|
||||||
<function>Describe()</function>,
|
<function>Describe()</function>,
|
||||||
<function>CheckNew()</function>,
|
<function>CheckNew()</function>,
|
||||||
<function>Update()</function>,
|
<function>Acquire()</function>,
|
||||||
|
<function>Install()</function>,
|
||||||
<function>Vacuum()</function>,
|
<function>Vacuum()</function>,
|
||||||
<function>GetAppStream()</function>,
|
<function>GetAppStream()</function>,
|
||||||
<function>GetVersion()</function>,
|
<function>GetVersion()</function>,
|
||||||
|
|||||||
@ -497,17 +497,6 @@
|
|||||||
in a user namespace with the current user mapped to the root user to make sure the files and
|
in a user namespace with the current user mapped to the root user to make sure the files and
|
||||||
directories in the image are owned by the root user.</para>
|
directories in the image are owned by the root user.</para>
|
||||||
|
|
||||||
<para>Note that when populating XFS filesystems with <command>systemd-repart</command> and loop
|
|
||||||
devices are not available, populating XFS filesystems with files containing spaces, tabs or newlines
|
|
||||||
might fail on old versions of
|
|
||||||
<citerefentry project='man-pages'><refentrytitle>mkfs.xfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
|
||||||
due to limitations of its protofile format.</para>
|
|
||||||
|
|
||||||
<para>Note that when populating XFS filesystems with <command>systemd-repart</command> and loop
|
|
||||||
devices are not available, extended attributes will not be copied into generated XFS filesystems
|
|
||||||
due to limitations <citerefentry project='man-pages'><refentrytitle>mkfs.xfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
|
|
||||||
protofile format.</para>
|
|
||||||
|
|
||||||
<para>This option cannot be combined with <varname>CopyBlocks=</varname>.</para>
|
<para>This option cannot be combined with <varname>CopyBlocks=</varname>.</para>
|
||||||
|
|
||||||
<para>When
|
<para>When
|
||||||
@ -517,6 +506,9 @@
|
|||||||
<option>--image=</option> or <option>--root=</option> switches are used, the source paths are taken
|
<option>--image=</option> or <option>--root=</option> switches are used, the source paths are taken
|
||||||
relative to the specified root directory or disk image root.</para>
|
relative to the specified root directory or disk image root.</para>
|
||||||
|
|
||||||
|
<para>Note that when <varname>CopyFiles=</varname> is used with <varname>Format=xfs</varname>,
|
||||||
|
<command>xfsprogs</command> 6.17 or newer is required.</para>
|
||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v247"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v247"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|||||||
@ -1797,6 +1797,17 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>ConditionPathIsSocket=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para><varname>ConditionPathIsSocket=</varname> is similar to
|
||||||
|
<varname>ConditionPathExists=</varname> but verifies that a certain path exists and is a
|
||||||
|
socket.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v260"/>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>ConditionDirectoryNotEmpty=</varname></term>
|
<term><varname>ConditionDirectoryNotEmpty=</varname></term>
|
||||||
|
|
||||||
@ -2052,6 +2063,7 @@
|
|||||||
<term><varname>AssertPathIsMountPoint=</varname></term>
|
<term><varname>AssertPathIsMountPoint=</varname></term>
|
||||||
<term><varname>AssertPathIsReadWrite=</varname></term>
|
<term><varname>AssertPathIsReadWrite=</varname></term>
|
||||||
<term><varname>AssertPathIsEncrypted=</varname></term>
|
<term><varname>AssertPathIsEncrypted=</varname></term>
|
||||||
|
<term><varname>AssertPathIsSocket=</varname></term>
|
||||||
<term><varname>AssertDirectoryNotEmpty=</varname></term>
|
<term><varname>AssertDirectoryNotEmpty=</varname></term>
|
||||||
<term><varname>AssertFileNotEmpty=</varname></term>
|
<term><varname>AssertFileNotEmpty=</varname></term>
|
||||||
<term><varname>AssertFileIsExecutable=</varname></term>
|
<term><varname>AssertFileIsExecutable=</varname></term>
|
||||||
|
|||||||
@ -895,7 +895,6 @@ foreach option : ['adm-gid',
|
|||||||
'video-gid',
|
'video-gid',
|
||||||
'wheel-gid',
|
'wheel-gid',
|
||||||
'systemd-journal-gid',
|
'systemd-journal-gid',
|
||||||
'systemd-journal-uid',
|
|
||||||
'systemd-network-uid',
|
'systemd-network-uid',
|
||||||
'systemd-resolve-uid',
|
'systemd-resolve-uid',
|
||||||
'systemd-timesync-uid']
|
'systemd-timesync-uid']
|
||||||
|
|||||||
@ -328,8 +328,6 @@ option('wheel-gid', type : 'integer', value : 0,
|
|||||||
description : 'soft-static allocation for the "wheel" group')
|
description : 'soft-static allocation for the "wheel" group')
|
||||||
option('systemd-journal-gid', type : 'integer', value : 0,
|
option('systemd-journal-gid', type : 'integer', value : 0,
|
||||||
description : 'soft-static allocation for the systemd-journal group')
|
description : 'soft-static allocation for the systemd-journal group')
|
||||||
option('systemd-journal-uid', type : 'integer', value : 0,
|
|
||||||
description : 'soft-static allocation for the systemd-journal user')
|
|
||||||
option('systemd-network-uid', type : 'integer', value : 0,
|
option('systemd-network-uid', type : 'integer', value : 0,
|
||||||
description : 'soft-static allocation for the systemd-network user')
|
description : 'soft-static allocation for the systemd-network user')
|
||||||
option('systemd-resolve-uid', type : 'integer', value : 0,
|
option('systemd-resolve-uid', type : 'integer', value : 0,
|
||||||
|
|||||||
@ -97,6 +97,7 @@ typedef enum RuntimeScope RuntimeScope;
|
|||||||
typedef enum TimestampStyle TimestampStyle;
|
typedef enum TimestampStyle TimestampStyle;
|
||||||
typedef enum UnitActiveState UnitActiveState;
|
typedef enum UnitActiveState UnitActiveState;
|
||||||
typedef enum UnitDependency UnitDependency;
|
typedef enum UnitDependency UnitDependency;
|
||||||
|
typedef enum UnitNameMangle UnitNameMangle;
|
||||||
typedef enum UnitType UnitType;
|
typedef enum UnitType UnitType;
|
||||||
typedef enum WaitFlags WaitFlags;
|
typedef enum WaitFlags WaitFlags;
|
||||||
|
|
||||||
|
|||||||
@ -366,6 +366,7 @@ Unit.ConditionPathIsSymbolicLink, config_parse_unit_condition_path,
|
|||||||
Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, conditions)
|
Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, conditions)
|
||||||
Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, conditions)
|
Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, conditions)
|
||||||
Unit.ConditionPathIsEncrypted, config_parse_unit_condition_path, CONDITION_PATH_IS_ENCRYPTED, offsetof(Unit, conditions)
|
Unit.ConditionPathIsEncrypted, config_parse_unit_condition_path, CONDITION_PATH_IS_ENCRYPTED, offsetof(Unit, conditions)
|
||||||
|
Unit.ConditionPathIsSocket, config_parse_unit_condition_path, CONDITION_PATH_IS_SOCKET, offsetof(Unit, conditions)
|
||||||
Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, conditions)
|
Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, conditions)
|
||||||
Unit.ConditionFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, conditions)
|
Unit.ConditionFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, conditions)
|
||||||
Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, conditions)
|
Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, conditions)
|
||||||
@ -401,6 +402,7 @@ Unit.AssertPathIsSymbolicLink, config_parse_unit_condition_path,
|
|||||||
Unit.AssertPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, asserts)
|
Unit.AssertPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, asserts)
|
||||||
Unit.AssertPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, asserts)
|
Unit.AssertPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, asserts)
|
||||||
Unit.AssertPathIsEncrypted, config_parse_unit_condition_path, CONDITION_PATH_IS_ENCRYPTED, offsetof(Unit, asserts)
|
Unit.AssertPathIsEncrypted, config_parse_unit_condition_path, CONDITION_PATH_IS_ENCRYPTED, offsetof(Unit, asserts)
|
||||||
|
Unit.AssertPathIsSocket, config_parse_unit_condition_path, CONDITION_PATH_IS_SOCKET, offsetof(Unit, asserts)
|
||||||
Unit.AssertDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, asserts)
|
Unit.AssertDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, asserts)
|
||||||
Unit.AssertFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, asserts)
|
Unit.AssertFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, asserts)
|
||||||
Unit.AssertFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, asserts)
|
Unit.AssertFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, asserts)
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "chase.h"
|
#include "chase.h"
|
||||||
#include "devnum-util.h"
|
#include "devnum-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
|
#include "glob-util.h"
|
||||||
#include "journal-internal.h"
|
#include "journal-internal.h"
|
||||||
#include "journalctl.h"
|
#include "journalctl.h"
|
||||||
#include "journalctl-filter.h"
|
#include "journalctl-filter.h"
|
||||||
@ -71,6 +72,116 @@ static int add_dmesg(sd_journal *j) {
|
|||||||
return sd_journal_add_conjunction(j);
|
return sd_journal_add_conjunction(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int journal_add_unit_matches(
|
||||||
|
sd_journal *j,
|
||||||
|
MatchUnitFlag flags,
|
||||||
|
UnitNameMangle mangle_flags,
|
||||||
|
char * const *system_units,
|
||||||
|
uid_t uid,
|
||||||
|
char * const *user_units) {
|
||||||
|
|
||||||
|
_cleanup_strv_free_ char **patterns = NULL;
|
||||||
|
bool added = false;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(j);
|
||||||
|
|
||||||
|
if (strv_isempty(system_units) && strv_isempty(user_units))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
STRV_FOREACH(i, system_units) {
|
||||||
|
_cleanup_free_ char *u = NULL;
|
||||||
|
|
||||||
|
r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | mangle_flags, &u);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (string_is_glob(u)) {
|
||||||
|
r = strv_consume(&patterns, TAKE_PTR(u));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
|
r = add_matches_for_unit_full(j, flags, u);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
r = sd_journal_add_disjunction(j);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strv_isempty(patterns)) {
|
||||||
|
_cleanup_set_free_ Set *units = NULL;
|
||||||
|
|
||||||
|
r = get_possible_units(j, SYSTEM_UNITS_FULL, patterns, &units);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
char *u;
|
||||||
|
SET_FOREACH(u, units) {
|
||||||
|
r = add_matches_for_unit_full(j, flags, u);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
r = sd_journal_add_disjunction(j);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
patterns = strv_free(patterns);
|
||||||
|
|
||||||
|
STRV_FOREACH(i, user_units) {
|
||||||
|
_cleanup_free_ char *u = NULL;
|
||||||
|
|
||||||
|
r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | mangle_flags, &u);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (string_is_glob(u)) {
|
||||||
|
r = strv_consume(&patterns, TAKE_PTR(u));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
|
r = add_matches_for_user_unit_full(j, flags, uid, u);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
r = sd_journal_add_disjunction(j);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!strv_isempty(patterns)) {
|
||||||
|
_cleanup_set_free_ Set *units = NULL;
|
||||||
|
|
||||||
|
r = get_possible_units(j, USER_UNITS_FULL, patterns, &units);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
char *u;
|
||||||
|
SET_FOREACH(u, units) {
|
||||||
|
r = add_matches_for_user_unit_full(j, flags, uid, u);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
r = sd_journal_add_disjunction(j);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Complain if the user request matches but nothing whatsoever was found, since otherwise everything
|
||||||
|
* would be matched. */
|
||||||
|
if (!added)
|
||||||
|
return -ENODATA;
|
||||||
|
|
||||||
|
return sd_journal_add_conjunction(j);
|
||||||
|
}
|
||||||
|
|
||||||
static int add_units(sd_journal *j) {
|
static int add_units(sd_journal *j) {
|
||||||
MatchUnitFlag flags = MATCH_UNIT_ALL;
|
MatchUnitFlag flags = MATCH_UNIT_ALL;
|
||||||
|
|
||||||
@ -82,7 +193,9 @@ static int add_units(sd_journal *j) {
|
|||||||
if (arg_directory || arg_root || arg_file_stdin || arg_file || arg_machine)
|
if (arg_directory || arg_root || arg_file_stdin || arg_file || arg_machine)
|
||||||
flags &= ~MATCH_UNIT_COREDUMP_UID;
|
flags &= ~MATCH_UNIT_COREDUMP_UID;
|
||||||
|
|
||||||
return journal_add_unit_matches(j, flags, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, arg_system_units, arg_user_units);
|
return journal_add_unit_matches(j, flags, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
||||||
|
arg_system_units,
|
||||||
|
UID_INVALID, arg_user_units);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_syslog_identifier(sd_journal *j) {
|
static int add_syslog_identifier(sd_journal *j) {
|
||||||
|
|||||||
@ -3,4 +3,12 @@
|
|||||||
|
|
||||||
#include "shared-forward.h"
|
#include "shared-forward.h"
|
||||||
|
|
||||||
|
int journal_add_unit_matches(
|
||||||
|
sd_journal *j,
|
||||||
|
MatchUnitFlag flags,
|
||||||
|
UnitNameMangle mangle_flags,
|
||||||
|
char * const *system_units,
|
||||||
|
uid_t uid,
|
||||||
|
char * const *user_units);
|
||||||
|
|
||||||
int add_filters(sd_journal *j, char **matches);
|
int add_filters(sd_journal *j, char **matches);
|
||||||
|
|||||||
@ -177,108 +177,6 @@ int get_possible_units(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int journal_add_unit_matches(sd_journal *j, MatchUnitFlag flags, UnitNameMangle mangle_flags, char **system_units, char **user_units) {
|
|
||||||
_cleanup_strv_free_ char **patterns = NULL;
|
|
||||||
bool added = false;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(j);
|
|
||||||
|
|
||||||
if (strv_isempty(system_units) && strv_isempty(user_units))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
STRV_FOREACH(i, system_units) {
|
|
||||||
_cleanup_free_ char *u = NULL;
|
|
||||||
|
|
||||||
r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | mangle_flags, &u);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (string_is_glob(u)) {
|
|
||||||
r = strv_consume(&patterns, TAKE_PTR(u));
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
r = add_matches_for_unit_full(j, flags, u);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
r = sd_journal_add_disjunction(j);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
added = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strv_isempty(patterns)) {
|
|
||||||
_cleanup_set_free_ Set *units = NULL;
|
|
||||||
|
|
||||||
r = get_possible_units(j, SYSTEM_UNITS_FULL, patterns, &units);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
char *u;
|
|
||||||
SET_FOREACH(u, units) {
|
|
||||||
r = add_matches_for_unit_full(j, flags, u);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
r = sd_journal_add_disjunction(j);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
added = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
patterns = strv_free(patterns);
|
|
||||||
|
|
||||||
STRV_FOREACH(i, user_units) {
|
|
||||||
_cleanup_free_ char *u = NULL;
|
|
||||||
|
|
||||||
r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | mangle_flags, &u);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (string_is_glob(u)) {
|
|
||||||
r = strv_consume(&patterns, TAKE_PTR(u));
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
r = add_matches_for_user_unit_full(j, flags, u);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
r = sd_journal_add_disjunction(j);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
added = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strv_isempty(patterns)) {
|
|
||||||
_cleanup_set_free_ Set *units = NULL;
|
|
||||||
|
|
||||||
r = get_possible_units(j, USER_UNITS_FULL, patterns, &units);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
char *u;
|
|
||||||
SET_FOREACH(u, units) {
|
|
||||||
r = add_matches_for_user_unit_full(j, flags, u);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
r = sd_journal_add_disjunction(j);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
added = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Complain if the user request matches but nothing whatsoever was found, since otherwise everything
|
|
||||||
* would be matched. */
|
|
||||||
if (!added)
|
|
||||||
return -ENODATA;
|
|
||||||
|
|
||||||
return sd_journal_add_conjunction(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
int acquire_unit(sd_journal *j, const char *option_name, const char **ret_unit, LogIdType *ret_type) {
|
int acquire_unit(sd_journal *j, const char *option_name, const char **ret_unit, LogIdType *ret_type) {
|
||||||
size_t n;
|
size_t n;
|
||||||
int r;
|
int r;
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "shared-forward.h"
|
#include "shared-forward.h"
|
||||||
#include "logs-show.h"
|
#include "logs-show.h"
|
||||||
#include "unit-name.h"
|
|
||||||
|
|
||||||
/* The lists below are supposed to return the superset of unit names possibly matched by rules added with
|
/* The lists below are supposed to return the superset of unit names possibly matched by rules added with
|
||||||
* add_matches_for_unit() and add_matches_for_user_unit(). */
|
* add_matches_for_unit() and add_matches_for_user_unit(). */
|
||||||
@ -32,6 +31,5 @@ int acquire_journal(sd_journal **ret);
|
|||||||
bool journal_boot_has_effect(sd_journal *j);
|
bool journal_boot_has_effect(sd_journal *j);
|
||||||
int journal_acquire_boot(sd_journal *j);
|
int journal_acquire_boot(sd_journal *j);
|
||||||
int get_possible_units(sd_journal *j, const char *fields, char * const *patterns, Set **ret);
|
int get_possible_units(sd_journal *j, const char *fields, char * const *patterns, Set **ret);
|
||||||
int journal_add_unit_matches(sd_journal *j, MatchUnitFlag flags, UnitNameMangle mangle_flags, char **system_units, char **user_units);
|
|
||||||
int acquire_unit(sd_journal *j, const char *option_name, const char **ret_unit, LogIdType *ret_type);
|
int acquire_unit(sd_journal *j, const char *option_name, const char **ret_unit, LogIdType *ret_type);
|
||||||
int journal_acquire_invocation(sd_journal *j);
|
int journal_acquire_invocation(sd_journal *j);
|
||||||
|
|||||||
@ -4,25 +4,30 @@
|
|||||||
#include "sd-varlink.h"
|
#include "sd-varlink.h"
|
||||||
|
|
||||||
#include "journal-internal.h"
|
#include "journal-internal.h"
|
||||||
#include "journalctl-util.h"
|
#include "journalctl.h"
|
||||||
|
#include "journalctl-filter.h"
|
||||||
#include "journalctl-varlink-server.h"
|
#include "journalctl-varlink-server.h"
|
||||||
#include "json-util.h"
|
#include "json-util.h"
|
||||||
#include "log.h"
|
|
||||||
#include "logs-show.h"
|
#include "logs-show.h"
|
||||||
#include "output-mode.h"
|
#include "output-mode.h"
|
||||||
|
#include "runtime-scope.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
#include "unit-name.h" /* IWYU pragma: keep */
|
||||||
|
#include "user-util.h"
|
||||||
#include "varlink-util.h"
|
#include "varlink-util.h"
|
||||||
|
|
||||||
typedef struct GetEntriesParameters {
|
typedef struct GetEntriesParameters {
|
||||||
char **units;
|
char **units;
|
||||||
char **user_units;
|
char **user_units;
|
||||||
const char *namespace;
|
const char *namespace;
|
||||||
|
uid_t uid;
|
||||||
int priority;
|
int priority;
|
||||||
uint64_t limit;
|
uint64_t limit;
|
||||||
} GetEntriesParameters;
|
} GetEntriesParameters;
|
||||||
|
|
||||||
static void get_entries_parameters_done(GetEntriesParameters *p) {
|
static void get_entries_parameters_done(GetEntriesParameters *p) {
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
p->units = strv_free(p->units);
|
p->units = strv_free(p->units);
|
||||||
p->user_units = strv_free(p->user_units);
|
p->user_units = strv_free(p->user_units);
|
||||||
}
|
}
|
||||||
@ -31,6 +36,7 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
|||||||
|
|
||||||
static const sd_json_dispatch_field dispatch_table[] = {
|
static const sd_json_dispatch_field dispatch_table[] = {
|
||||||
{ "units", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(GetEntriesParameters, units), 0 },
|
{ "units", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(GetEntriesParameters, units), 0 },
|
||||||
|
{ "uid", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, offsetof(GetEntriesParameters, uid), 0 },
|
||||||
{ "userUnits", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(GetEntriesParameters, user_units), 0 },
|
{ "userUnits", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(GetEntriesParameters, user_units), 0 },
|
||||||
{ "namespace", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetEntriesParameters, namespace), 0 },
|
{ "namespace", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetEntriesParameters, namespace), 0 },
|
||||||
{ "priority", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_log_level, offsetof(GetEntriesParameters, priority), 0 },
|
{ "priority", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_log_level, offsetof(GetEntriesParameters, priority), 0 },
|
||||||
@ -39,6 +45,7 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
|||||||
};
|
};
|
||||||
|
|
||||||
_cleanup_(get_entries_parameters_done) GetEntriesParameters p = {
|
_cleanup_(get_entries_parameters_done) GetEntriesParameters p = {
|
||||||
|
.uid = UID_INVALID,
|
||||||
.priority = -1,
|
.priority = -1,
|
||||||
};
|
};
|
||||||
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
||||||
@ -51,23 +58,26 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
|||||||
if (r != 0)
|
if (r != 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (arg_varlink_runtime_scope == RUNTIME_SCOPE_SYSTEM && p.user_units && !uid_is_valid(p.uid))
|
||||||
|
return sd_varlink_error_invalid_parameter_name(link, "uid");
|
||||||
|
|
||||||
/* systemd ships with sensible defaults for the system/user services and the socket permissions so we
|
/* systemd ships with sensible defaults for the system/user services and the socket permissions so we
|
||||||
* do not need to do extra sd_varlink_get_peer_uid() or policykit checks here */
|
* do not need to do extra sd_varlink_get_peer_uid() or policykit checks here */
|
||||||
r = sd_journal_open_namespace(&j, p.namespace, SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_ASSUME_IMMUTABLE);
|
r = sd_journal_open_namespace(&j, p.namespace, SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_ASSUME_IMMUTABLE);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to open journal: %m");
|
return r;
|
||||||
|
|
||||||
r = journal_add_unit_matches(j, MATCH_UNIT_ALL, /* mangle_flags= */ 0, p.units, p.user_units);
|
r = journal_add_unit_matches(j, MATCH_UNIT_ALL, /* mangle_flags= */ 0, p.units, p.uid, p.user_units);
|
||||||
if (r == -ENODATA)
|
if (r == -ENODATA)
|
||||||
return sd_varlink_error(link, SD_VARLINK_ERROR_INVALID_PARAMETER, NULL);
|
return sd_varlink_error(link, "io.systemd.JournalAccess.NoMatches", NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to add unit matches: %m");
|
return r;
|
||||||
|
|
||||||
if (p.priority >= 0) {
|
if (p.priority >= 0) {
|
||||||
for (int i = 0; i <= p.priority; i++) {
|
for (int i = 0; i <= p.priority; i++) {
|
||||||
r = journal_add_matchf(j, "PRIORITY=%d", i);
|
r = journal_add_matchf(j, "PRIORITY=%d", i);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to add priority match: %m");
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_journal_add_conjunction(j);
|
r = sd_journal_add_conjunction(j);
|
||||||
@ -78,7 +88,7 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
|||||||
/* this simulates "journalctl -n $p.limit" */
|
/* this simulates "journalctl -n $p.limit" */
|
||||||
r = sd_journal_seek_tail(j);
|
r = sd_journal_seek_tail(j);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to seek to tail: %m");
|
return r;
|
||||||
|
|
||||||
/* FIXME: this restriction should be removed eventually */
|
/* FIXME: this restriction should be removed eventually */
|
||||||
if (p.limit > 10000)
|
if (p.limit > 10000)
|
||||||
@ -86,6 +96,10 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
|||||||
|
|
||||||
uint64_t n = p.limit == 0 ? 100 : p.limit;
|
uint64_t n = p.limit == 0 ? 100 : p.limit;
|
||||||
|
|
||||||
|
r = sd_journal_previous_skip(j, n + 1);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = varlink_set_sentinel(link, "io.systemd.JournalAccess.NoEntries");
|
r = varlink_set_sentinel(link, "io.systemd.JournalAccess.NoEntries");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -93,9 +107,9 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
|||||||
for (uint64_t i = 0; i < n; i++) {
|
for (uint64_t i = 0; i < n; i++) {
|
||||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *entry = NULL;
|
_cleanup_(sd_json_variant_unrefp) sd_json_variant *entry = NULL;
|
||||||
|
|
||||||
r = sd_journal_previous(j);
|
r = sd_journal_next(j);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to iterate journal: %m");
|
return r;
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -105,7 +119,7 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
|||||||
if (r == 0)
|
if (r == 0)
|
||||||
continue; /* skip corrupted entry */
|
continue; /* skip corrupted entry */
|
||||||
|
|
||||||
r = sd_varlink_replybo(link, SD_JSON_BUILD_PAIR("entry", SD_JSON_BUILD_VARIANT(entry)));
|
r = sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_VARIANT("entry", entry));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "pcre2-util.h"
|
#include "pcre2-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
|
#include "runtime-scope.h"
|
||||||
#include "set.h"
|
#include "set.h"
|
||||||
#include "static-destruct.h"
|
#include "static-destruct.h"
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
@ -111,7 +112,9 @@ pcre2_code *arg_compiled_pattern = NULL;
|
|||||||
PatternCompileCase arg_case = PATTERN_COMPILE_CASE_AUTO;
|
PatternCompileCase arg_case = PATTERN_COMPILE_CASE_AUTO;
|
||||||
ImagePolicy *arg_image_policy = NULL;
|
ImagePolicy *arg_image_policy = NULL;
|
||||||
bool arg_synchronize_on_exit = false;
|
bool arg_synchronize_on_exit = false;
|
||||||
|
|
||||||
static bool arg_varlink = false;
|
static bool arg_varlink = false;
|
||||||
|
RuntimeScope arg_varlink_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_cursor, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_cursor, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_cursor_file, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_cursor_file, freep);
|
||||||
@ -486,7 +489,35 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
|
return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
arg_varlink = true;
|
arg_varlink = true;
|
||||||
arg_pager_flags |= PAGER_DISABLE;
|
|
||||||
|
static const struct option varlink_options[] = {
|
||||||
|
{ "system", no_argument, NULL, ARG_SYSTEM },
|
||||||
|
{ "user", no_argument, NULL, ARG_USER },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
while ((c = getopt_long(argc, argv, "", varlink_options, NULL)) >= 0)
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
|
||||||
|
case ARG_SYSTEM:
|
||||||
|
arg_varlink_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_USER:
|
||||||
|
arg_varlink_runtime_scope = RUNTIME_SCOPE_USER;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg_varlink_runtime_scope < 0)
|
||||||
|
return log_error_errno(arg_varlink_runtime_scope, "Cannot run in Varlink mode with no runtime scope specified.");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -94,3 +94,6 @@ extern bool arg_synchronize_on_exit;
|
|||||||
static inline bool arg_lines_needs_seek_end(void) {
|
static inline bool arg_lines_needs_seek_end(void) {
|
||||||
return arg_lines >= 0 && !arg_lines_oldest;
|
return arg_lines >= 0 && !arg_lines_oldest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Only used for varlink server invocation */
|
||||||
|
extern RuntimeScope arg_varlink_runtime_scope;
|
||||||
|
|||||||
@ -693,20 +693,46 @@ int device_clone_with_db(sd_device *device, sd_device **ret) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_cleanup_tags(sd_device *device) {
|
int device_copy_all_tags(sd_device *dest, sd_device *src) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(dest);
|
||||||
|
|
||||||
|
if (!src)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FOREACH_DEVICE_TAG(src, tag) {
|
||||||
|
r = device_add_tag(dest, tag, /* both= */ false);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_cleanup_tags(sd_device *device, sd_device *original) {
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(device);
|
assert(device);
|
||||||
|
|
||||||
device->all_tags = set_free(device->all_tags);
|
_cleanup_set_free_ Set *saved = TAKE_PTR(device->all_tags);
|
||||||
device->current_tags = set_free(device->current_tags);
|
device->current_tags = set_free(device->current_tags);
|
||||||
device->property_tags_outdated = true;
|
device->property_tags_outdated = true;
|
||||||
device->tags_generation++;
|
device->tags_generation++;
|
||||||
|
|
||||||
|
r = device_copy_all_tags(device, original);
|
||||||
|
if (r < 0) {
|
||||||
|
set_free_and_replace(device->all_tags, saved);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_cleanup_devlinks(sd_device *device) {
|
void device_cleanup_devlinks(sd_device *device) {
|
||||||
assert(device);
|
assert(device);
|
||||||
|
|
||||||
set_free(device->devlinks);
|
device->devlinks = set_free(device->devlinks);
|
||||||
device->devlinks = NULL;
|
|
||||||
device->property_devlinks_outdated = true;
|
device->property_devlinks_outdated = true;
|
||||||
device->devlinks_generation++;
|
device->devlinks_generation++;
|
||||||
}
|
}
|
||||||
@ -743,15 +769,9 @@ static int device_tag(sd_device *device, const char *tag, bool add) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
|
int device_tag_index(sd_device *device, bool add) {
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
if (add && device_old)
|
|
||||||
/* delete possible left-over tags */
|
|
||||||
FOREACH_DEVICE_TAG(device_old, tag)
|
|
||||||
if (!sd_device_has_tag(device, tag))
|
|
||||||
RET_GATHER(r, device_tag(device_old, tag, false));
|
|
||||||
|
|
||||||
FOREACH_DEVICE_TAG(device, tag)
|
FOREACH_DEVICE_TAG(device, tag)
|
||||||
RET_GATHER(r, device_tag(device, tag, add));
|
RET_GATHER(r, device_tag(device, tag, add));
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,8 @@ int device_add_property(sd_device *device, const char *key, const char *value);
|
|||||||
int device_add_propertyf(sd_device *device, const char *key, const char *format, ...) _printf_(3, 4);
|
int device_add_propertyf(sd_device *device, const char *key, const char *format, ...) _printf_(3, 4);
|
||||||
int device_add_tag(sd_device *device, const char *tag, bool both);
|
int device_add_tag(sd_device *device, const char *tag, bool both);
|
||||||
void device_remove_tag(sd_device *device, const char *tag);
|
void device_remove_tag(sd_device *device, const char *tag);
|
||||||
void device_cleanup_tags(sd_device *device);
|
int device_copy_all_tags(sd_device *dest, sd_device *src);
|
||||||
|
int device_cleanup_tags(sd_device *device, sd_device *original);
|
||||||
void device_cleanup_devlinks(sd_device *device);
|
void device_cleanup_devlinks(sd_device *device);
|
||||||
|
|
||||||
uint64_t device_get_properties_generation(sd_device *device);
|
uint64_t device_get_properties_generation(sd_device *device);
|
||||||
@ -58,7 +59,7 @@ int device_get_properties_strv(sd_device *device, char ***ret);
|
|||||||
|
|
||||||
int device_clone_with_db(sd_device *device, sd_device **ret);
|
int device_clone_with_db(sd_device *device, sd_device **ret);
|
||||||
|
|
||||||
int device_tag_index(sd_device *device, sd_device *device_old, bool add);
|
int device_tag_index(sd_device *device, bool add);
|
||||||
bool device_should_have_db(sd_device *device);
|
bool device_should_have_db(sd_device *device);
|
||||||
int device_has_db(sd_device *device);
|
int device_has_db(sd_device *device);
|
||||||
int device_update_db(sd_device *device);
|
int device_update_db(sd_device *device);
|
||||||
|
|||||||
@ -992,6 +992,14 @@ static int condition_test_path_is_encrypted(Condition *c, char **env) {
|
|||||||
return r > 0;
|
return r > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int condition_test_path_is_socket(Condition *c, char **env) {
|
||||||
|
assert(c);
|
||||||
|
assert(c->parameter);
|
||||||
|
assert(c->type == CONDITION_PATH_IS_SOCKET);
|
||||||
|
|
||||||
|
return is_socket(c->parameter) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int condition_test_directory_not_empty(Condition *c, char **env) {
|
static int condition_test_directory_not_empty(Condition *c, char **env) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -1233,6 +1241,7 @@ int condition_test(Condition *c, char **env) {
|
|||||||
[CONDITION_PATH_IS_MOUNT_POINT] = condition_test_path_is_mount_point,
|
[CONDITION_PATH_IS_MOUNT_POINT] = condition_test_path_is_mount_point,
|
||||||
[CONDITION_PATH_IS_READ_WRITE] = condition_test_path_is_read_write,
|
[CONDITION_PATH_IS_READ_WRITE] = condition_test_path_is_read_write,
|
||||||
[CONDITION_PATH_IS_ENCRYPTED] = condition_test_path_is_encrypted,
|
[CONDITION_PATH_IS_ENCRYPTED] = condition_test_path_is_encrypted,
|
||||||
|
[CONDITION_PATH_IS_SOCKET] = condition_test_path_is_socket,
|
||||||
[CONDITION_DIRECTORY_NOT_EMPTY] = condition_test_directory_not_empty,
|
[CONDITION_DIRECTORY_NOT_EMPTY] = condition_test_directory_not_empty,
|
||||||
[CONDITION_FILE_NOT_EMPTY] = condition_test_file_not_empty,
|
[CONDITION_FILE_NOT_EMPTY] = condition_test_file_not_empty,
|
||||||
[CONDITION_FILE_IS_EXECUTABLE] = condition_test_file_is_executable,
|
[CONDITION_FILE_IS_EXECUTABLE] = condition_test_file_is_executable,
|
||||||
@ -1370,6 +1379,7 @@ static const char* const _condition_type_table[_CONDITION_TYPE_MAX] = {
|
|||||||
[CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
|
[CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
|
||||||
[CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
|
[CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
|
||||||
[CONDITION_PATH_IS_ENCRYPTED] = "ConditionPathIsEncrypted",
|
[CONDITION_PATH_IS_ENCRYPTED] = "ConditionPathIsEncrypted",
|
||||||
|
[CONDITION_PATH_IS_SOCKET] = "ConditionPathIsSocket",
|
||||||
[CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
|
[CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
|
||||||
[CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
|
[CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
|
||||||
[CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
|
[CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
|
||||||
@ -1425,6 +1435,7 @@ static const char* const _assert_type_table[_CONDITION_TYPE_MAX] = {
|
|||||||
[CONDITION_PATH_IS_MOUNT_POINT] = "AssertPathIsMountPoint",
|
[CONDITION_PATH_IS_MOUNT_POINT] = "AssertPathIsMountPoint",
|
||||||
[CONDITION_PATH_IS_READ_WRITE] = "AssertPathIsReadWrite",
|
[CONDITION_PATH_IS_READ_WRITE] = "AssertPathIsReadWrite",
|
||||||
[CONDITION_PATH_IS_ENCRYPTED] = "AssertPathIsEncrypted",
|
[CONDITION_PATH_IS_ENCRYPTED] = "AssertPathIsEncrypted",
|
||||||
|
[CONDITION_PATH_IS_SOCKET] = "AssertPathIsSocket",
|
||||||
[CONDITION_DIRECTORY_NOT_EMPTY] = "AssertDirectoryNotEmpty",
|
[CONDITION_DIRECTORY_NOT_EMPTY] = "AssertDirectoryNotEmpty",
|
||||||
[CONDITION_FILE_NOT_EMPTY] = "AssertFileNotEmpty",
|
[CONDITION_FILE_NOT_EMPTY] = "AssertFileNotEmpty",
|
||||||
[CONDITION_FILE_IS_EXECUTABLE] = "AssertFileIsExecutable",
|
[CONDITION_FILE_IS_EXECUTABLE] = "AssertFileIsExecutable",
|
||||||
|
|||||||
@ -34,6 +34,7 @@ typedef enum ConditionType {
|
|||||||
CONDITION_PATH_IS_MOUNT_POINT,
|
CONDITION_PATH_IS_MOUNT_POINT,
|
||||||
CONDITION_PATH_IS_READ_WRITE,
|
CONDITION_PATH_IS_READ_WRITE,
|
||||||
CONDITION_PATH_IS_ENCRYPTED,
|
CONDITION_PATH_IS_ENCRYPTED,
|
||||||
|
CONDITION_PATH_IS_SOCKET,
|
||||||
CONDITION_DIRECTORY_NOT_EMPTY,
|
CONDITION_DIRECTORY_NOT_EMPTY,
|
||||||
CONDITION_FILE_NOT_EMPTY,
|
CONDITION_FILE_NOT_EMPTY,
|
||||||
CONDITION_FILE_IS_EXECUTABLE,
|
CONDITION_FILE_IS_EXECUTABLE,
|
||||||
@ -104,6 +105,7 @@ static inline bool condition_takes_path(ConditionType t) {
|
|||||||
CONDITION_PATH_IS_MOUNT_POINT,
|
CONDITION_PATH_IS_MOUNT_POINT,
|
||||||
CONDITION_PATH_IS_READ_WRITE,
|
CONDITION_PATH_IS_READ_WRITE,
|
||||||
CONDITION_PATH_IS_ENCRYPTED,
|
CONDITION_PATH_IS_ENCRYPTED,
|
||||||
|
CONDITION_PATH_IS_SOCKET,
|
||||||
CONDITION_DIRECTORY_NOT_EMPTY,
|
CONDITION_DIRECTORY_NOT_EMPTY,
|
||||||
CONDITION_FILE_NOT_EMPTY,
|
CONDITION_FILE_NOT_EMPTY,
|
||||||
CONDITION_FILE_IS_EXECUTABLE,
|
CONDITION_FILE_IS_EXECUTABLE,
|
||||||
|
|||||||
@ -1193,17 +1193,20 @@ static int update_json_data_split(
|
|||||||
return update_json_data(h, flags, name, eq + 1, size - fieldlen - 1);
|
return update_json_data(h, flags, name, eq + 1, size - fieldlen - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int journal_entry_to_json(sd_journal *j, OutputFlags flags, const Set *output_fields, sd_json_variant **ret) {
|
int journal_entry_to_json(
|
||||||
|
sd_journal *j,
|
||||||
|
OutputFlags flags,
|
||||||
|
const Set *output_fields,
|
||||||
|
sd_json_variant **ret) {
|
||||||
|
|
||||||
char usecbuf[CONST_MAX(DECIMAL_STR_MAX(usec_t), DECIMAL_STR_MAX(uint64_t))];
|
char usecbuf[CONST_MAX(DECIMAL_STR_MAX(usec_t), DECIMAL_STR_MAX(uint64_t))];
|
||||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *object = NULL;
|
|
||||||
_cleanup_hashmap_free_ Hashmap *h = NULL;
|
|
||||||
sd_id128_t journal_boot_id, seqnum_id;
|
sd_id128_t journal_boot_id, seqnum_id;
|
||||||
_cleanup_free_ char *cursor = NULL;
|
_cleanup_free_ char *cursor = NULL;
|
||||||
usec_t realtime, monotonic;
|
usec_t realtime, monotonic;
|
||||||
sd_json_variant **array = NULL;
|
|
||||||
JsonData *d;
|
|
||||||
uint64_t seqnum;
|
uint64_t seqnum;
|
||||||
|
const char *corrupted_what = NULL;
|
||||||
|
_cleanup_hashmap_free_ Hashmap *h = NULL;
|
||||||
|
_cleanup_free_ sd_json_variant **array = NULL;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -1214,32 +1217,32 @@ int journal_entry_to_json(sd_journal *j, OutputFlags flags, const Set *output_fi
|
|||||||
|
|
||||||
r = sd_journal_get_cursor(j, &cursor);
|
r = sd_journal_get_cursor(j, &cursor);
|
||||||
if (IN_SET(r, -EBADMSG, -EADDRNOTAVAIL)) {
|
if (IN_SET(r, -EBADMSG, -EADDRNOTAVAIL)) {
|
||||||
log_debug_errno(r, "Unable to determine cursor of entry, assuming bad or partially written entry: %m");
|
corrupted_what = "cursor";
|
||||||
return 0;
|
goto corrupted_skip;
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to get cursor: %m");
|
return log_error_errno(r, "Failed to get cursor: %m");
|
||||||
|
|
||||||
r = sd_journal_get_realtime_usec(j, &realtime);
|
r = sd_journal_get_realtime_usec(j, &realtime);
|
||||||
if (r == -EBADMSG) {
|
if (r == -EBADMSG) {
|
||||||
log_debug_errno(r, "Unable to read realtime timestamp of entry, assuming bad or partially written entry: %m");
|
corrupted_what = "realtime timestamp";
|
||||||
return 0;
|
goto corrupted_skip;
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to get realtime timestamp: %m");
|
return log_error_errno(r, "Failed to get realtime timestamp: %m");
|
||||||
|
|
||||||
r = sd_journal_get_monotonic_usec(j, &monotonic, &journal_boot_id);
|
r = sd_journal_get_monotonic_usec(j, &monotonic, &journal_boot_id);
|
||||||
if (r == -EBADMSG) {
|
if (r == -EBADMSG) {
|
||||||
log_debug_errno(r, "Unable to read monotonic timestamp of entry, assuming bad or partially written entry: %m");
|
corrupted_what = "monotonic timestamp";
|
||||||
return 0;
|
goto corrupted_skip;
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to get monotonic timestamp: %m");
|
return log_error_errno(r, "Failed to get monotonic timestamp: %m");
|
||||||
|
|
||||||
r = sd_journal_get_seqnum(j, &seqnum, &seqnum_id);
|
r = sd_journal_get_seqnum(j, &seqnum, &seqnum_id);
|
||||||
if (r == -EBADMSG) {
|
if (r == -EBADMSG) {
|
||||||
log_debug_errno(r, "Unable to read sequence number of entry, assuming bad or partially written entry: %m");
|
corrupted_what = "sequence number";
|
||||||
return 0;
|
goto corrupted_skip;
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to get seqnum: %m");
|
return log_error_errno(r, "Failed to get seqnum: %m");
|
||||||
@ -1294,29 +1297,32 @@ int journal_entry_to_json(sd_journal *j, OutputFlags flags, const Set *output_fi
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
array = new(sd_json_variant*, hashmap_size(h)*2);
|
array = new(sd_json_variant*, hashmap_size(h) * 2);
|
||||||
if (!array)
|
if (!array)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
CLEANUP_ARRAY(array, n, sd_json_variant_unref_many);
|
JsonData *d;
|
||||||
|
|
||||||
HASHMAP_FOREACH(d, h) {
|
HASHMAP_FOREACH(d, h) {
|
||||||
assert(sd_json_variant_elements(d->values) > 0);
|
assert(sd_json_variant_elements(d->values) > 0);
|
||||||
|
|
||||||
array[n++] = sd_json_variant_ref(d->name);
|
array[n++] = d->name;
|
||||||
|
|
||||||
if (sd_json_variant_elements(d->values) == 1)
|
if (sd_json_variant_elements(d->values) == 1)
|
||||||
array[n++] = sd_json_variant_ref(sd_json_variant_by_index(d->values, 0));
|
array[n++] = sd_json_variant_by_index(d->values, 0);
|
||||||
else
|
else
|
||||||
array[n++] = sd_json_variant_ref(d->values);
|
array[n++] = d->values;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_json_variant_new_object(&object, array, n);
|
r = sd_json_variant_new_object(ret, array, n);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to allocate JSON object: %m");
|
return log_error_errno(r, "Failed to allocate JSON object: %m");
|
||||||
|
|
||||||
*ret = TAKE_PTR(object);
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
corrupted_skip:
|
||||||
|
log_debug_errno(r, "Unable to determine %s of entry, assuming bad or partially written entry: %m", ASSERT_PTR(corrupted_what));
|
||||||
|
*ret = NULL;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int output_json(
|
static int output_json(
|
||||||
@ -1761,13 +1767,15 @@ int add_matches_for_unit_full(sd_journal *j, MatchUnitFlag flags, const char *un
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_matches_for_user_unit_full(sd_journal *j, MatchUnitFlag flags, const char *unit) {
|
int add_matches_for_user_unit_full(sd_journal *j, MatchUnitFlag flags, uid_t uid, const char *unit) {
|
||||||
uid_t uid = getuid();
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(j);
|
assert(j);
|
||||||
assert(unit);
|
assert(unit);
|
||||||
|
|
||||||
|
if (uid == UID_INVALID)
|
||||||
|
uid = getuid();
|
||||||
|
|
||||||
(void) (
|
(void) (
|
||||||
/* Look for messages from the user service itself */
|
/* Look for messages from the user service itself */
|
||||||
(r = journal_add_match_pair(j, "_SYSTEMD_USER_UNIT", unit)) ||
|
(r = journal_add_match_pair(j, "_SYSTEMD_USER_UNIT", unit)) ||
|
||||||
@ -2004,7 +2012,7 @@ static int set_matches_for_discover_id(
|
|||||||
return add_matches_for_unit_full(j, /* flags= */ 0, unit);
|
return add_matches_for_unit_full(j, /* flags= */ 0, unit);
|
||||||
|
|
||||||
if (type == LOG_USER_UNIT_INVOCATION_ID)
|
if (type == LOG_USER_UNIT_INVOCATION_ID)
|
||||||
return add_matches_for_user_unit_full(j, /* flags= */ 0, unit);
|
return add_matches_for_user_unit_full(j, /* flags= */ 0, UID_INVALID, unit);
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,9 +57,9 @@ int add_matches_for_unit_full(sd_journal *j, MatchUnitFlag flags, const char *un
|
|||||||
static inline int add_matches_for_unit(sd_journal *j, const char *unit) {
|
static inline int add_matches_for_unit(sd_journal *j, const char *unit) {
|
||||||
return add_matches_for_unit_full(j, MATCH_UNIT_ALL, unit);
|
return add_matches_for_unit_full(j, MATCH_UNIT_ALL, unit);
|
||||||
}
|
}
|
||||||
int add_matches_for_user_unit_full(sd_journal *j, MatchUnitFlag flags, const char *unit);
|
int add_matches_for_user_unit_full(sd_journal *j, MatchUnitFlag flags, uid_t uid, const char *unit);
|
||||||
static inline int add_matches_for_user_unit(sd_journal *j, const char *unit) {
|
static inline int add_matches_for_user_unit(sd_journal *j, const char *unit) {
|
||||||
return add_matches_for_user_unit_full(j, MATCH_UNIT_ALL, unit);
|
return add_matches_for_user_unit_full(j, MATCH_UNIT_ALL, UID_INVALID, unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
int show_journal_by_unit(
|
int show_journal_by_unit(
|
||||||
|
|||||||
@ -4,10 +4,6 @@
|
|||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "fd-util.h"
|
|
||||||
#include "fileio.h"
|
|
||||||
#include "format-util.h"
|
|
||||||
#include "fs-util.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "mkfs-util.h"
|
#include "mkfs-util.h"
|
||||||
#include "mount-util.h"
|
#include "mount-util.h"
|
||||||
@ -15,12 +11,10 @@
|
|||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "recurse-dir.h"
|
#include "recurse-dir.h"
|
||||||
#include "rm-rf.h"
|
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "stdio-util.h"
|
#include "stdio-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "tmpfile-util.h"
|
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
|
|
||||||
int mkfs_exists(const char *fstype) {
|
int mkfs_exists(const char *fstype) {
|
||||||
@ -171,154 +165,6 @@ static int do_mcopy(const char *node, const char *root) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct ProtofileData {
|
|
||||||
FILE *file;
|
|
||||||
bool has_filename_with_spaces;
|
|
||||||
const char *tmpdir;
|
|
||||||
} ProtofileData;
|
|
||||||
|
|
||||||
static int protofile_print_item(
|
|
||||||
RecurseDirEvent event,
|
|
||||||
const char *path,
|
|
||||||
int dir_fd,
|
|
||||||
int inode_fd,
|
|
||||||
const struct dirent *de,
|
|
||||||
const struct statx *sx,
|
|
||||||
void *userdata) {
|
|
||||||
|
|
||||||
ProtofileData *data = ASSERT_PTR(userdata);
|
|
||||||
_cleanup_free_ char *copy = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (event == RECURSE_DIR_LEAVE) {
|
|
||||||
fputs("$\n", data->file);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IN_SET(event, RECURSE_DIR_ENTER, RECURSE_DIR_ENTRY))
|
|
||||||
return RECURSE_DIR_CONTINUE;
|
|
||||||
|
|
||||||
char type = S_ISDIR(sx->stx_mode) ? 'd' :
|
|
||||||
S_ISREG(sx->stx_mode) ? '-' :
|
|
||||||
S_ISLNK(sx->stx_mode) ? 'l' :
|
|
||||||
S_ISFIFO(sx->stx_mode) ? 'p' :
|
|
||||||
S_ISBLK(sx->stx_mode) ? 'b' :
|
|
||||||
S_ISCHR(sx->stx_mode) ? 'c' : 0;
|
|
||||||
if (type == 0)
|
|
||||||
return RECURSE_DIR_CONTINUE;
|
|
||||||
|
|
||||||
/* The protofile format does not support spaces in filenames as whitespace is used as a token
|
|
||||||
* delimiter. To work around this limitation, mkfs.xfs allows escaping whitespace by using the /
|
|
||||||
* character (which isn't allowed in filenames and as such can be used to escape whitespace). See
|
|
||||||
* https://lore.kernel.org/linux-xfs/20230222090303.h6tujm7y32gjhgal@andromeda/T/#m8066b3e7d62a080ee7434faac4861d944e64493b
|
|
||||||
* for more information. */
|
|
||||||
|
|
||||||
if (strchr(de->d_name, ' ')) {
|
|
||||||
copy = strdup(de->d_name);
|
|
||||||
if (!copy)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
string_replace_char(copy, ' ', '/');
|
|
||||||
data->has_filename_with_spaces = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(data->file, "%s %c%c%c%03o "UID_FMT" "GID_FMT" ",
|
|
||||||
copy ?: de->d_name,
|
|
||||||
type,
|
|
||||||
sx->stx_mode & S_ISUID ? 'u' : '-',
|
|
||||||
sx->stx_mode & S_ISGID ? 'g' : '-',
|
|
||||||
(unsigned) (sx->stx_mode & 0777),
|
|
||||||
sx->stx_uid, sx->stx_gid);
|
|
||||||
|
|
||||||
if (S_ISREG(sx->stx_mode)) {
|
|
||||||
_cleanup_free_ char *p = NULL;
|
|
||||||
|
|
||||||
/* While we can escape whitespace in the filename, we cannot escape whitespace in the source
|
|
||||||
* path, so hack around that by creating a symlink to the path in a temporary directory and
|
|
||||||
* using the symlink as the source path instead. */
|
|
||||||
|
|
||||||
if (strchr(path, ' ')) {
|
|
||||||
r = tempfn_random_child(data->tmpdir, "mkfs-xfs", &p);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to generate random child name in %s: %m", data->tmpdir);
|
|
||||||
|
|
||||||
if (symlink(path, p) < 0)
|
|
||||||
return log_error_errno(errno, "Failed to symlink %s to %s: %m", p, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs(p ?: path, data->file);
|
|
||||||
} else if (S_ISLNK(sx->stx_mode)) {
|
|
||||||
_cleanup_free_ char *p = NULL;
|
|
||||||
|
|
||||||
r = readlinkat_malloc(dir_fd, de->d_name, &p);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to read symlink %s: %m", path);
|
|
||||||
|
|
||||||
/* If we have a symlink to a path with whitespace in it, we're out of luck, as there's no way
|
|
||||||
* to encode that in the mkfs.xfs protofile format. */
|
|
||||||
|
|
||||||
if (strchr(p, ' '))
|
|
||||||
return log_error_errno(r, "Symlinks to paths containing whitespace are not supported by mkfs.xfs: %m");
|
|
||||||
|
|
||||||
fputs(p, data->file);
|
|
||||||
} else if (S_ISBLK(sx->stx_mode) || S_ISCHR(sx->stx_mode))
|
|
||||||
fprintf(data->file, "%" PRIu32 " %" PRIu32, sx->stx_rdev_major, sx->stx_rdev_minor);
|
|
||||||
|
|
||||||
fputc('\n', data->file);
|
|
||||||
|
|
||||||
return RECURSE_DIR_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int make_protofile(const char *root, char **ret_path, bool *ret_has_filename_with_spaces, char **ret_tmpdir) {
|
|
||||||
_cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL;
|
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
|
||||||
_cleanup_(unlink_and_freep) char *p = NULL;
|
|
||||||
struct ProtofileData data = {};
|
|
||||||
const char *vt;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(ret_path);
|
|
||||||
assert(ret_has_filename_with_spaces);
|
|
||||||
assert(ret_tmpdir);
|
|
||||||
|
|
||||||
r = var_tmp_dir(&vt);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to get persistent temporary directory: %m");
|
|
||||||
|
|
||||||
r = fopen_temporary_child(vt, &f, &p);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to open temporary file: %m");
|
|
||||||
|
|
||||||
/* Explicitly use /tmp here because this directory cannot have spaces its path. */
|
|
||||||
r = mkdtemp_malloc("/tmp/systemd-mkfs-XXXXXX", &tmpdir);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to create temporary directory: %m");
|
|
||||||
|
|
||||||
data.file = f;
|
|
||||||
data.tmpdir = tmpdir;
|
|
||||||
|
|
||||||
fputs("/\n"
|
|
||||||
"0 0\n"
|
|
||||||
"d--755 0 0\n", f);
|
|
||||||
|
|
||||||
r = recurse_dir_at(AT_FDCWD, root, STATX_TYPE|STATX_MODE|STATX_UID|STATX_GID, UINT_MAX,
|
|
||||||
RECURSE_DIR_SORT, protofile_print_item, &data);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to recurse through %s: %m", root);
|
|
||||||
|
|
||||||
fputs("$\n", f);
|
|
||||||
|
|
||||||
r = fflush_and_check(f);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to flush %s: %m", p);
|
|
||||||
|
|
||||||
*ret_path = TAKE_PTR(p);
|
|
||||||
*ret_has_filename_with_spaces = data.has_filename_with_spaces;
|
|
||||||
*ret_tmpdir = TAKE_PTR(tmpdir);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int make_filesystem(
|
int make_filesystem(
|
||||||
const char *node,
|
const char *node,
|
||||||
const char *fstype,
|
const char *fstype,
|
||||||
@ -333,8 +179,6 @@ int make_filesystem(
|
|||||||
|
|
||||||
_cleanup_free_ char *mkfs = NULL, *mangled_label = NULL;
|
_cleanup_free_ char *mkfs = NULL, *mangled_label = NULL;
|
||||||
_cleanup_strv_free_ char **argv = NULL, **env = NULL;
|
_cleanup_strv_free_ char **argv = NULL, **env = NULL;
|
||||||
_cleanup_(rm_rf_physical_and_freep) char *protofile_tmpdir = NULL;
|
|
||||||
_cleanup_(unlink_and_freep) char *protofile = NULL;
|
|
||||||
char vol_id[CONST_MAX(SD_ID128_UUID_STRING_MAX, 8U + 1U)] = {};
|
char vol_id[CONST_MAX(SD_ID128_UUID_STRING_MAX, 8U + 1U)] = {};
|
||||||
int stdio_fds[3] = { -EBADF, STDERR_FILENO, STDERR_FILENO};
|
int stdio_fds[3] = { -EBADF, STDERR_FILENO, STDERR_FILENO};
|
||||||
ForkFlags fork_flags = FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_WAIT|
|
ForkFlags fork_flags = FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_WAIT|
|
||||||
@ -560,26 +404,8 @@ int make_filesystem(
|
|||||||
if (!FLAGS_SET(flags, MKFS_DISCARD) && strv_extend(&argv, "-K") < 0)
|
if (!FLAGS_SET(flags, MKFS_DISCARD) && strv_extend(&argv, "-K") < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (root) {
|
if (root && strv_extend_many(&argv, "-p", root) < 0)
|
||||||
bool has_filename_with_spaces = false;
|
|
||||||
_cleanup_free_ char *protofile_with_opt = NULL;
|
|
||||||
|
|
||||||
r = make_protofile(root, &protofile, &has_filename_with_spaces, &protofile_tmpdir);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
/* Gross hack to make mkfs.xfs interpret slashes as spaces so we can encode filenames
|
|
||||||
* with spaces in the protofile format. */
|
|
||||||
if (has_filename_with_spaces)
|
|
||||||
protofile_with_opt = strjoin("slashes_are_spaces=1,", protofile);
|
|
||||||
else
|
|
||||||
protofile_with_opt = strdup(protofile);
|
|
||||||
if (!protofile_with_opt)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
if (strv_extend_many(&argv, "-p", protofile_with_opt) < 0)
|
|
||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
|
||||||
|
|
||||||
if (sector_size > 0) {
|
if (sector_size > 0) {
|
||||||
if (strv_extend(&argv, "-s") < 0)
|
if (strv_extend(&argv, "-s") < 0)
|
||||||
|
|||||||
@ -26,6 +26,7 @@ typedef enum DnssecMode DnssecMode;
|
|||||||
typedef enum Fido2EnrollFlags Fido2EnrollFlags;
|
typedef enum Fido2EnrollFlags Fido2EnrollFlags;
|
||||||
typedef enum KeySourceType KeySourceType;
|
typedef enum KeySourceType KeySourceType;
|
||||||
typedef enum LabelFixFlags LabelFixFlags;
|
typedef enum LabelFixFlags LabelFixFlags;
|
||||||
|
typedef enum MatchUnitFlag MatchUnitFlag;
|
||||||
typedef enum MountInNamespaceFlags MountInNamespaceFlags;
|
typedef enum MountInNamespaceFlags MountInNamespaceFlags;
|
||||||
typedef enum NamePolicy NamePolicy;
|
typedef enum NamePolicy NamePolicy;
|
||||||
typedef enum OutputFlags OutputFlags;
|
typedef enum OutputFlags OutputFlags;
|
||||||
|
|||||||
@ -274,6 +274,29 @@ _noreturn_ void log_test_failed_internal(const char *file, int line, const char
|
|||||||
})
|
})
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __COVERITY__
|
||||||
|
# define ASSERT_OK_NE(expr1, expr2) \
|
||||||
|
({ \
|
||||||
|
typeof(expr1) _expr1 = (expr1); \
|
||||||
|
typeof(expr2) _expr2 = (expr2); \
|
||||||
|
__coverity_check__(_expr1 != _expr2); \
|
||||||
|
_expr1; \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
# define ASSERT_OK_NE(expr1, expr2) \
|
||||||
|
({ \
|
||||||
|
typeof(expr1) _expr1 = (expr1); \
|
||||||
|
typeof(expr2) _expr2 = (expr2); \
|
||||||
|
if (_expr1 < 0) \
|
||||||
|
log_test_failed("Expected \"%s\" to succeed, but got error: %"PRIiMAX"/%s", \
|
||||||
|
#expr1, (intmax_t) _expr1, ERRNO_NAME(_expr1)); \
|
||||||
|
if (_expr1 == _expr2) \
|
||||||
|
log_test_failed("Expected \"%s != %s\", got %"PRIiMAX" != %"PRIiMAX, \
|
||||||
|
#expr1, #expr2, (intmax_t) _expr1, (intmax_t) _expr2); \
|
||||||
|
_expr1; \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
/* For functions that return a boolean on success and set errno on failure. */
|
/* For functions that return a boolean on success and set errno on failure. */
|
||||||
#ifdef __COVERITY__
|
#ifdef __COVERITY__
|
||||||
# define ASSERT_OK_ERRNO(expr) \
|
# define ASSERT_OK_ERRNO(expr) \
|
||||||
|
|||||||
@ -7,6 +7,8 @@ static SD_VARLINK_DEFINE_METHOD_FULL(
|
|||||||
SD_VARLINK_REQUIRES_MORE,
|
SD_VARLINK_REQUIRES_MORE,
|
||||||
SD_VARLINK_FIELD_COMMENT("Show messages for the specified systemd units (e.g. ['foo.service'])."),
|
SD_VARLINK_FIELD_COMMENT("Show messages for the specified systemd units (e.g. ['foo.service'])."),
|
||||||
SD_VARLINK_DEFINE_INPUT(units, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY),
|
SD_VARLINK_DEFINE_INPUT(units, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY),
|
||||||
|
SD_VARLINK_FIELD_COMMENT("UID to match user units for"),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(uid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||||
SD_VARLINK_FIELD_COMMENT("Show messages for the specified user units (e.g. ['foo.service'])."),
|
SD_VARLINK_FIELD_COMMENT("Show messages for the specified user units (e.g. ['foo.service'])."),
|
||||||
SD_VARLINK_DEFINE_INPUT(userUnits, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY),
|
SD_VARLINK_DEFINE_INPUT(userUnits, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY),
|
||||||
SD_VARLINK_FIELD_COMMENT("If specified, shows the log data of the specified namespace, otherwise the default namespace."),
|
SD_VARLINK_FIELD_COMMENT("If specified, shows the log data of the specified namespace, otherwise the default namespace."),
|
||||||
@ -16,8 +18,9 @@ static SD_VARLINK_DEFINE_METHOD_FULL(
|
|||||||
SD_VARLINK_FIELD_COMMENT("Maximum number of entries to return. Defaults to 100, capped at 10000."),
|
SD_VARLINK_FIELD_COMMENT("Maximum number of entries to return. Defaults to 100, capped at 10000."),
|
||||||
SD_VARLINK_DEFINE_INPUT(limit, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
SD_VARLINK_DEFINE_INPUT(limit, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||||
SD_VARLINK_FIELD_COMMENT("The journal entry in flat JSON format, matching journalctl --output=json."),
|
SD_VARLINK_FIELD_COMMENT("The journal entry in flat JSON format, matching journalctl --output=json."),
|
||||||
SD_VARLINK_DEFINE_OUTPUT(entry, SD_VARLINK_OBJECT, SD_VARLINK_NULLABLE));
|
SD_VARLINK_DEFINE_OUTPUT(entry, SD_VARLINK_OBJECT, 0));
|
||||||
|
|
||||||
|
static SD_VARLINK_DEFINE_ERROR(NoMatches);
|
||||||
static SD_VARLINK_DEFINE_ERROR(NoEntries);
|
static SD_VARLINK_DEFINE_ERROR(NoEntries);
|
||||||
|
|
||||||
SD_VARLINK_DEFINE_INTERFACE(
|
SD_VARLINK_DEFINE_INTERFACE(
|
||||||
@ -26,5 +29,7 @@ SD_VARLINK_DEFINE_INTERFACE(
|
|||||||
SD_VARLINK_INTERFACE_COMMENT("Journal log read APIs"),
|
SD_VARLINK_INTERFACE_COMMENT("Journal log read APIs"),
|
||||||
SD_VARLINK_SYMBOL_COMMENT("Retrieve journal log entries, optionally filtered by unit, priority, etc."),
|
SD_VARLINK_SYMBOL_COMMENT("Retrieve journal log entries, optionally filtered by unit, priority, etc."),
|
||||||
&vl_method_GetEntries,
|
&vl_method_GetEntries,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("No matches found for specified unit patterns"),
|
||||||
|
&vl_error_NoMatches,
|
||||||
SD_VARLINK_SYMBOL_COMMENT("No journal entries matched the specified filters."),
|
SD_VARLINK_SYMBOL_COMMENT("No journal entries matched the specified filters."),
|
||||||
&vl_error_NoEntries);
|
&vl_error_NoEntries);
|
||||||
|
|||||||
@ -64,7 +64,11 @@
|
|||||||
|
|
||||||
<allow send_destination="org.freedesktop.sysupdate1"
|
<allow send_destination="org.freedesktop.sysupdate1"
|
||||||
send_interface="org.freedesktop.sysupdate1.Target"
|
send_interface="org.freedesktop.sysupdate1.Target"
|
||||||
send_member="Update"/>
|
send_member="Acquire"/>
|
||||||
|
|
||||||
|
<allow send_destination="org.freedesktop.sysupdate1"
|
||||||
|
send_interface="org.freedesktop.sysupdate1.Target"
|
||||||
|
send_member="Install"/>
|
||||||
|
|
||||||
<allow send_destination="org.freedesktop.sysupdate1"
|
<allow send_destination="org.freedesktop.sysupdate1"
|
||||||
send_interface="org.freedesktop.sysupdate1.Target"
|
send_interface="org.freedesktop.sysupdate1.Target"
|
||||||
|
|||||||
@ -100,7 +100,8 @@ typedef enum JobType {
|
|||||||
JOB_LIST,
|
JOB_LIST,
|
||||||
JOB_DESCRIBE,
|
JOB_DESCRIBE,
|
||||||
JOB_CHECK_NEW,
|
JOB_CHECK_NEW,
|
||||||
JOB_UPDATE,
|
JOB_ACQUIRE,
|
||||||
|
JOB_INSTALL,
|
||||||
JOB_VACUUM,
|
JOB_VACUUM,
|
||||||
JOB_DESCRIBE_FEATURE,
|
JOB_DESCRIBE_FEATURE,
|
||||||
_JOB_TYPE_MAX,
|
_JOB_TYPE_MAX,
|
||||||
@ -121,7 +122,7 @@ struct Job {
|
|||||||
|
|
||||||
JobType type;
|
JobType type;
|
||||||
bool offline;
|
bool offline;
|
||||||
char *version; /* Passed into sysupdate for JOB_DESCRIBE and JOB_UPDATE */
|
char *version; /* Passed into sysupdate for JOB_DESCRIBE, JOB_ACQUIRE and JOB_INSTALL */
|
||||||
char *feature; /* Passed into sysupdate for JOB_DESCRIBE_FEATURE */
|
char *feature; /* Passed into sysupdate for JOB_DESCRIBE_FEATURE */
|
||||||
|
|
||||||
unsigned progress_percent;
|
unsigned progress_percent;
|
||||||
@ -153,7 +154,8 @@ static const char* const job_type_table[_JOB_TYPE_MAX] = {
|
|||||||
[JOB_LIST] = "list",
|
[JOB_LIST] = "list",
|
||||||
[JOB_DESCRIBE] = "describe",
|
[JOB_DESCRIBE] = "describe",
|
||||||
[JOB_CHECK_NEW] = "check-new",
|
[JOB_CHECK_NEW] = "check-new",
|
||||||
[JOB_UPDATE] = "update",
|
[JOB_ACQUIRE] = "acquire",
|
||||||
|
[JOB_INSTALL] = "install",
|
||||||
[JOB_VACUUM] = "vacuum",
|
[JOB_VACUUM] = "vacuum",
|
||||||
[JOB_DESCRIBE_FEATURE] = "describe-feature",
|
[JOB_DESCRIBE_FEATURE] = "describe-feature",
|
||||||
};
|
};
|
||||||
@ -220,6 +222,11 @@ static int job_new(JobType type, Target *t, sd_bus_message *msg, JobComplete com
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is Job in the set of jobs which require Target.busy to be set so they run exclusively? */
|
||||||
|
static bool job_requires_busy(Job *j) {
|
||||||
|
return IN_SET(j->type, JOB_ACQUIRE, JOB_INSTALL, JOB_VACUUM);
|
||||||
|
}
|
||||||
|
|
||||||
static int job_parse_child_output(int _fd, sd_json_variant **ret) {
|
static int job_parse_child_output(int _fd, sd_json_variant **ret) {
|
||||||
_cleanup_close_ int fd = ASSERT_FD(_fd); /* Take ownership of the passed fd */
|
_cleanup_close_ int fd = ASSERT_FD(_fd); /* Take ownership of the passed fd */
|
||||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||||
@ -332,7 +339,7 @@ static int job_on_exit(sd_event_source *s, const siginfo_t *si, void *userdata)
|
|||||||
assert(s);
|
assert(s);
|
||||||
assert(si);
|
assert(si);
|
||||||
|
|
||||||
if (IN_SET(j->type, JOB_UPDATE, JOB_VACUUM)) {
|
if (job_requires_busy(j)) {
|
||||||
assert(j->target->busy);
|
assert(j->target->busy);
|
||||||
j->target->busy = false;
|
j->target->busy = false;
|
||||||
}
|
}
|
||||||
@ -430,7 +437,7 @@ static int job_start(Job *j) {
|
|||||||
|
|
||||||
assert(j);
|
assert(j);
|
||||||
|
|
||||||
if (IN_SET(j->type, JOB_UPDATE, JOB_VACUUM) && j->target->busy)
|
if (job_requires_busy(j) && j->target->busy)
|
||||||
return log_notice_errno(SYNTHETIC_ERRNO(EBUSY), "Target %s busy, ignoring job.", j->target->name);
|
return log_notice_errno(SYNTHETIC_ERRNO(EBUSY), "Target %s busy, ignoring job.", j->target->name);
|
||||||
|
|
||||||
stdout_fd = memfd_new("sysupdate-stdout");
|
stdout_fd = memfd_new("sysupdate-stdout");
|
||||||
@ -453,8 +460,8 @@ static int job_start(Job *j) {
|
|||||||
NULL, /* maybe --verify=no */
|
NULL, /* maybe --verify=no */
|
||||||
NULL, /* maybe --component=, --root=, or --image= */
|
NULL, /* maybe --component=, --root=, or --image= */
|
||||||
NULL, /* maybe --offline */
|
NULL, /* maybe --offline */
|
||||||
NULL, /* list, check-new, update, vacuum, features */
|
NULL, /* list, check-new, acquire, update, vacuum, features */
|
||||||
NULL, /* maybe version (for list, update), maybe feature (features) */
|
NULL, /* maybe version (for list, acquire, update), maybe feature (features) */
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
size_t k = 2;
|
size_t k = 2;
|
||||||
@ -479,7 +486,7 @@ static int job_start(Job *j) {
|
|||||||
if (target_arg)
|
if (target_arg)
|
||||||
cmd[k++] = target_arg;
|
cmd[k++] = target_arg;
|
||||||
|
|
||||||
if (j->offline)
|
if (j->offline || j->type == JOB_INSTALL) /* install is implemented as `update --offline` */
|
||||||
cmd[k++] = "--offline";
|
cmd[k++] = "--offline";
|
||||||
|
|
||||||
switch (j->type) {
|
switch (j->type) {
|
||||||
@ -497,8 +504,13 @@ static int job_start(Job *j) {
|
|||||||
cmd[k++] = "check-new";
|
cmd[k++] = "check-new";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JOB_UPDATE:
|
case JOB_ACQUIRE:
|
||||||
cmd[k++] = "update";
|
cmd[k++] = "acquire";
|
||||||
|
cmd[k++] = empty_to_null(j->version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JOB_INSTALL:
|
||||||
|
cmd[k++] = "update"; /* install is implemented as `update --offline` */
|
||||||
cmd[k++] = empty_to_null(j->version);
|
cmd[k++] = empty_to_null(j->version);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -547,7 +559,7 @@ static int job_start(Job *j) {
|
|||||||
|
|
||||||
j->stdout_fd = TAKE_FD(stdout_fd);
|
j->stdout_fd = TAKE_FD(stdout_fd);
|
||||||
|
|
||||||
if (IN_SET(j->type, JOB_UPDATE, JOB_VACUUM))
|
if (job_requires_busy(j))
|
||||||
j->target->busy = true;
|
j->target->busy = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -581,7 +593,8 @@ static int job_method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *
|
|||||||
action = "org.freedesktop.sysupdate1.check";
|
action = "org.freedesktop.sysupdate1.check";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JOB_UPDATE:
|
case JOB_ACQUIRE:
|
||||||
|
case JOB_INSTALL:
|
||||||
if (j->version)
|
if (j->version)
|
||||||
action = "org.freedesktop.sysupdate1.update-to-version";
|
action = "org.freedesktop.sysupdate1.update-to-version";
|
||||||
else
|
else
|
||||||
@ -1065,7 +1078,7 @@ static int target_method_check_new(sd_bus_message *msg, void *userdata, sd_bus_e
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int target_method_update_finished_early(
|
static int target_method_acquire_finished_early(
|
||||||
sd_bus_message *msg,
|
sd_bus_message *msg,
|
||||||
const Job *j,
|
const Job *j,
|
||||||
sd_json_variant *json,
|
sd_json_variant *json,
|
||||||
@ -1073,12 +1086,12 @@ static int target_method_update_finished_early(
|
|||||||
|
|
||||||
/* Called when job finishes w/ a successful exit code, but before any work begins.
|
/* Called when job finishes w/ a successful exit code, but before any work begins.
|
||||||
* This happens when there is no candidate (i.e. we're already up-to-date), or
|
* This happens when there is no candidate (i.e. we're already up-to-date), or
|
||||||
* specified update is already installed. */
|
* specified update is already acquired. */
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_NO_UPDATE_CANDIDATE,
|
return sd_bus_error_setf(error, BUS_ERROR_NO_UPDATE_CANDIDATE,
|
||||||
"Job exited successfully with no work to do, assume already updated");
|
"Job exited successfully with no work to do, assume already acquired");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int target_method_update_detach(sd_bus_message *msg, const Job *j) {
|
static int target_method_acquire_detach(sd_bus_message *msg, const Job *j) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(msg);
|
assert(msg);
|
||||||
@ -1091,7 +1104,7 @@ static int target_method_update_detach(sd_bus_message *msg, const Job *j) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int target_method_update(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
static int target_method_acquire(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||||
Target *t = ASSERT_PTR(userdata);
|
Target *t = ASSERT_PTR(userdata);
|
||||||
_cleanup_(job_freep) Job *j = NULL;
|
_cleanup_(job_freep) Job *j = NULL;
|
||||||
const char *version, *action;
|
const char *version, *action;
|
||||||
@ -1107,6 +1120,8 @@ static int target_method_update(sd_bus_message *msg, void *userdata, sd_bus_erro
|
|||||||
if (flags != 0)
|
if (flags != 0)
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be 0");
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be 0");
|
||||||
|
|
||||||
|
/* We don’t have a separate polkit action for acquire/install as they are both effectively (part of)
|
||||||
|
* an update anyway. */
|
||||||
if (isempty(version))
|
if (isempty(version))
|
||||||
action = "org.freedesktop.sysupdate1.update";
|
action = "org.freedesktop.sysupdate1.update";
|
||||||
else
|
else
|
||||||
@ -1130,10 +1145,94 @@ static int target_method_update(sd_bus_message *msg, void *userdata, sd_bus_erro
|
|||||||
if (r == 0)
|
if (r == 0)
|
||||||
return 1; /* Will call us back */
|
return 1; /* Will call us back */
|
||||||
|
|
||||||
r = job_new(JOB_UPDATE, t, msg, target_method_update_finished_early, &j);
|
r = job_new(JOB_ACQUIRE, t, msg, target_method_acquire_finished_early, &j);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
j->detach_cb = target_method_update_detach;
|
j->detach_cb = target_method_acquire_detach;
|
||||||
|
|
||||||
|
j->version = strdup(version);
|
||||||
|
if (!j->version)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
r = job_start(j);
|
||||||
|
if (r < 0)
|
||||||
|
return sd_bus_error_set_errnof(error, r, "Failed to start job: %m");
|
||||||
|
TAKE_PTR(j);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int target_method_install_finished_early(
|
||||||
|
sd_bus_message *msg,
|
||||||
|
const Job *j,
|
||||||
|
sd_json_variant *json,
|
||||||
|
sd_bus_error *error) {
|
||||||
|
|
||||||
|
/* Called when job finishes w/ a successful exit code, but before any work begins.
|
||||||
|
* This happens when there is no candidate (i.e. we're already up-to-date), or
|
||||||
|
* specified update is already installed. */
|
||||||
|
return sd_bus_error_setf(error, BUS_ERROR_NO_UPDATE_CANDIDATE,
|
||||||
|
"Job exited successfully with no work to do, assume already installed");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int target_method_install_detach(sd_bus_message *msg, const Job *j) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(msg);
|
||||||
|
assert(j);
|
||||||
|
|
||||||
|
r = sd_bus_reply_method_return(msg, "sto", j->version, j->id, j->object_path);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_parse_error(r);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int target_method_install(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||||
|
Target *t = ASSERT_PTR(userdata);
|
||||||
|
_cleanup_(job_freep) Job *j = NULL;
|
||||||
|
const char *version, *action;
|
||||||
|
uint64_t flags;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(msg);
|
||||||
|
|
||||||
|
r = sd_bus_message_read(msg, "st", &version, &flags);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (flags != 0)
|
||||||
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be 0");
|
||||||
|
|
||||||
|
/* We don’t have a separate polkit action for acquire/install as they are both effectively (part of)
|
||||||
|
* an update anyway. */
|
||||||
|
if (isempty(version))
|
||||||
|
action = "org.freedesktop.sysupdate1.update";
|
||||||
|
else
|
||||||
|
action = "org.freedesktop.sysupdate1.update-to-version";
|
||||||
|
|
||||||
|
const char *details[] = {
|
||||||
|
"class", target_class_to_string(t->class),
|
||||||
|
"name", t->name,
|
||||||
|
"version", version,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
r = bus_verify_polkit_async(
|
||||||
|
msg,
|
||||||
|
action,
|
||||||
|
details,
|
||||||
|
&t->manager->polkit_registry,
|
||||||
|
error);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
return 1; /* Will call us back */
|
||||||
|
|
||||||
|
r = job_new(JOB_INSTALL, t, msg, target_method_install_finished_early, &j);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
j->detach_cb = target_method_install_detach;
|
||||||
|
|
||||||
j->version = strdup(version);
|
j->version = strdup(version);
|
||||||
if (!j->version)
|
if (!j->version)
|
||||||
@ -1580,10 +1679,16 @@ static const sd_bus_vtable target_vtable[] = {
|
|||||||
target_method_check_new,
|
target_method_check_new,
|
||||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
|
||||||
SD_BUS_METHOD_WITH_ARGS("Update",
|
SD_BUS_METHOD_WITH_ARGS("Acquire",
|
||||||
SD_BUS_ARGS("s", new_version, "t", flags),
|
SD_BUS_ARGS("s", new_version, "t", flags),
|
||||||
SD_BUS_RESULT("s", new_version, "t", job_id, "o", job_path),
|
SD_BUS_RESULT("s", new_version, "t", job_id, "o", job_path),
|
||||||
target_method_update,
|
target_method_acquire,
|
||||||
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
|
||||||
|
SD_BUS_METHOD_WITH_ARGS("Install",
|
||||||
|
SD_BUS_ARGS("s", new_version, "t", flags),
|
||||||
|
SD_BUS_RESULT("s", new_version, "t", job_id, "o", job_path),
|
||||||
|
target_method_install,
|
||||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
|
||||||
SD_BUS_METHOD_WITH_ARGS("Vacuum",
|
SD_BUS_METHOD_WITH_ARGS("Vacuum",
|
||||||
|
|||||||
@ -72,6 +72,9 @@ typedef struct Operation {
|
|||||||
sd_event_source *job_interrupt_source;
|
sd_event_source *job_interrupt_source;
|
||||||
sd_bus_slot *job_properties_slot;
|
sd_bus_slot *job_properties_slot;
|
||||||
sd_bus_slot *job_finished_slot;
|
sd_bus_slot *job_finished_slot;
|
||||||
|
|
||||||
|
/* Only used for Acquire()/Install() operations: */
|
||||||
|
char *acquired_version;
|
||||||
} Operation;
|
} Operation;
|
||||||
|
|
||||||
static Operation* operation_free(Operation *p) {
|
static Operation* operation_free(Operation *p) {
|
||||||
@ -86,6 +89,7 @@ static Operation* operation_free(Operation *p) {
|
|||||||
assert_se(sd_event_exit(p->event, 0) >= 0);
|
assert_se(sd_event_exit(p->event, 0) >= 0);
|
||||||
|
|
||||||
free(p->job_path);
|
free(p->job_path);
|
||||||
|
free(p->acquired_version);
|
||||||
|
|
||||||
sd_event_source_disable_unref(p->job_interrupt_source);
|
sd_event_source_disable_unref(p->job_interrupt_source);
|
||||||
sd_bus_slot_unref(p->job_properties_slot);
|
sd_bus_slot_unref(p->job_properties_slot);
|
||||||
@ -334,6 +338,8 @@ typedef struct DescribeParams {
|
|||||||
bool newest;
|
bool newest;
|
||||||
bool available;
|
bool available;
|
||||||
bool installed;
|
bool installed;
|
||||||
|
bool partial;
|
||||||
|
bool pending;
|
||||||
bool obsolete;
|
bool obsolete;
|
||||||
bool protected;
|
bool protected;
|
||||||
bool incomplete;
|
bool incomplete;
|
||||||
@ -369,6 +375,8 @@ static int parse_describe(sd_bus_message *reply, Version *ret) {
|
|||||||
{ "newest", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, newest), 0 },
|
{ "newest", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, newest), 0 },
|
||||||
{ "available", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, available), 0 },
|
{ "available", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, available), 0 },
|
||||||
{ "installed", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, installed), 0 },
|
{ "installed", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, installed), 0 },
|
||||||
|
{ "partial", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, partial), 0 },
|
||||||
|
{ "pending", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, pending), 0 },
|
||||||
{ "obsolete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, obsolete), 0 },
|
{ "obsolete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, obsolete), 0 },
|
||||||
{ "protected", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, protected), 0 },
|
{ "protected", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, protected), 0 },
|
||||||
{ "incomplete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, incomplete), 0 },
|
{ "incomplete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, incomplete), 0 },
|
||||||
@ -386,6 +394,8 @@ static int parse_describe(sd_bus_message *reply, Version *ret) {
|
|||||||
SET_FLAG(p.v.flags, UPDATE_NEWEST, p.newest);
|
SET_FLAG(p.v.flags, UPDATE_NEWEST, p.newest);
|
||||||
SET_FLAG(p.v.flags, UPDATE_AVAILABLE, p.available);
|
SET_FLAG(p.v.flags, UPDATE_AVAILABLE, p.available);
|
||||||
SET_FLAG(p.v.flags, UPDATE_INSTALLED, p.installed);
|
SET_FLAG(p.v.flags, UPDATE_INSTALLED, p.installed);
|
||||||
|
SET_FLAG(p.v.flags, UPDATE_PARTIAL, p.partial);
|
||||||
|
SET_FLAG(p.v.flags, UPDATE_PENDING, p.pending);
|
||||||
SET_FLAG(p.v.flags, UPDATE_OBSOLETE, p.obsolete);
|
SET_FLAG(p.v.flags, UPDATE_OBSOLETE, p.obsolete);
|
||||||
SET_FLAG(p.v.flags, UPDATE_PROTECTED, p.protected);
|
SET_FLAG(p.v.flags, UPDATE_PROTECTED, p.protected);
|
||||||
SET_FLAG(p.v.flags, UPDATE_INCOMPLETE, p.incomplete);
|
SET_FLAG(p.v.flags, UPDATE_INCOMPLETE, p.incomplete);
|
||||||
@ -804,6 +814,7 @@ static int verb_check(int argc, char **argv, void *userdata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define UPDATE_PROGRESS_FAILED INT_MIN
|
#define UPDATE_PROGRESS_FAILED INT_MIN
|
||||||
|
#define UPDATE_PROGRESS_ACQUIRED (INT_MAX - 1)
|
||||||
#define UPDATE_PROGRESS_DONE INT_MAX
|
#define UPDATE_PROGRESS_DONE INT_MAX
|
||||||
/* Make sure it doesn't overlap w/ errno values */
|
/* Make sure it doesn't overlap w/ errno values */
|
||||||
assert_cc(UPDATE_PROGRESS_FAILED < -ERRNO_MAX);
|
assert_cc(UPDATE_PROGRESS_FAILED < -ERRNO_MAX);
|
||||||
@ -853,6 +864,10 @@ static int update_render_progress(sd_event_source *source, void *userdata) {
|
|||||||
clear_progress_bar_unbuffered(target);
|
clear_progress_bar_unbuffered(target);
|
||||||
fprintf(stderr, "%s: %s %s\n", target, RED_CROSS_MARK(), STRERROR(progress));
|
fprintf(stderr, "%s: %s %s\n", target, RED_CROSS_MARK(), STRERROR(progress));
|
||||||
total += 100;
|
total += 100;
|
||||||
|
} else if (progress == UPDATE_PROGRESS_ACQUIRED) {
|
||||||
|
clear_progress_bar_unbuffered(target);
|
||||||
|
fprintf(stderr, "%s: %s Installing\n", target, glyph(GLYPH_DOWNLOAD));
|
||||||
|
total += 100;
|
||||||
} else if (progress == UPDATE_PROGRESS_DONE) {
|
} else if (progress == UPDATE_PROGRESS_DONE) {
|
||||||
clear_progress_bar_unbuffered(target);
|
clear_progress_bar_unbuffered(target);
|
||||||
fprintf(stderr, "%s: %s Done\n", target, GREEN_CHECK_MARK());
|
fprintf(stderr, "%s: %s Done\n", target, GREEN_CHECK_MARK());
|
||||||
@ -920,7 +935,60 @@ static int update_properties_changed(sd_bus_message *m, void *userdata, sd_bus_e
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int update_finished(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
static int update_install_started(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
|
||||||
|
_cleanup_(operation_freep) Operation *op = ASSERT_PTR(userdata);
|
||||||
|
OrderedHashmap *map = ASSERT_PTR(op->userdata);
|
||||||
|
const sd_bus_error *e;
|
||||||
|
const char *job_path;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(reply);
|
||||||
|
|
||||||
|
e = sd_bus_message_get_error(reply);
|
||||||
|
if (e) {
|
||||||
|
r = -sd_bus_error_get_errno(e);
|
||||||
|
|
||||||
|
r = ordered_hashmap_replace(map, op->target_id, INT_TO_PTR(r));
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to update hashmap: %m");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_message_read(reply, "sto", NULL, &op->job_id, &job_path);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_parse_error(r);
|
||||||
|
r = free_and_strdup_warn(&op->job_path, job_path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Update this job in the hashmap. */
|
||||||
|
r = ordered_hashmap_replace(map, op->target_id, INT_TO_PTR(UPDATE_PROGRESS_ACQUIRED));
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to update hashmap: %m");
|
||||||
|
|
||||||
|
/* Register for progress notifications for this Install() D-Bus call; previously
|
||||||
|
* op->job_properties_slot was registered for progress notifications for the Acquire() D-Bus call. */
|
||||||
|
sd_bus_slot_unref(TAKE_PTR(op->job_properties_slot));
|
||||||
|
r = sd_bus_match_signal_async(
|
||||||
|
op->bus,
|
||||||
|
&op->job_properties_slot,
|
||||||
|
bus_sysupdate_mgr->destination,
|
||||||
|
job_path,
|
||||||
|
"org.freedesktop.DBus.Properties",
|
||||||
|
"PropertiesChanged",
|
||||||
|
update_properties_changed,
|
||||||
|
NULL,
|
||||||
|
op);
|
||||||
|
if (r < 0)
|
||||||
|
return log_bus_error(r, NULL, op->target_id, "listen for PropertiesChanged");
|
||||||
|
|
||||||
|
TAKE_PTR(op); /* update_install_finished/update_interrupted take ownership of the data */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int update_install_finished(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||||
_cleanup_(operation_freep) Operation *op = ASSERT_PTR(userdata);
|
_cleanup_(operation_freep) Operation *op = ASSERT_PTR(userdata);
|
||||||
OrderedHashmap *map = ASSERT_PTR(op->userdata);
|
OrderedHashmap *map = ASSERT_PTR(op->userdata);
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
@ -951,6 +1019,64 @@ static int update_finished(sd_bus_message *m, void *userdata, sd_bus_error *erro
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int update_acquire_finished(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||||
|
_cleanup_(operation_freep) Operation *op = ASSERT_PTR(userdata);
|
||||||
|
OrderedHashmap *map = ASSERT_PTR(op->userdata);
|
||||||
|
uint64_t id;
|
||||||
|
int r, status;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
|
||||||
|
r = sd_bus_message_read(m, "toi", &id, NULL, &status);
|
||||||
|
if (r < 0) {
|
||||||
|
bus_log_parse_error_debug(r);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id != op->job_id) {
|
||||||
|
TAKE_PTR(op);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == 0) /* success */
|
||||||
|
status = UPDATE_PROGRESS_ACQUIRED;
|
||||||
|
else if (status > 0) /* exit status without errno */
|
||||||
|
status = UPDATE_PROGRESS_FAILED; /* i.e. EXIT_FAILURE */
|
||||||
|
/* else errno */
|
||||||
|
|
||||||
|
r = ordered_hashmap_replace(map, op->target_id, INT_TO_PTR(status));
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to update hashmap: %m");
|
||||||
|
|
||||||
|
/* Renew the JobRemoved notification for the Install() call instead. */
|
||||||
|
sd_bus_slot_unref(op->job_finished_slot);
|
||||||
|
r = bus_match_signal_async(
|
||||||
|
op->bus, &op->job_finished_slot, bus_sysupdate_mgr, "JobRemoved", update_install_finished, NULL, op);
|
||||||
|
if (r < 0)
|
||||||
|
return log_bus_error(r, NULL, op->target_id, "listen for JobRemoved");
|
||||||
|
|
||||||
|
/* With the Acquire() call finished, immediately call Install() to deploy the downloaded update.
|
||||||
|
* This reuses the same Operation struct so the progress reporting continues to be done in the same
|
||||||
|
* slot in the terminal. */
|
||||||
|
r = sd_bus_call_method_async(
|
||||||
|
op->bus,
|
||||||
|
NULL,
|
||||||
|
bus_sysupdate_mgr->destination,
|
||||||
|
op->target_path,
|
||||||
|
SYSUPDATE_TARGET_INTERFACE,
|
||||||
|
"Install",
|
||||||
|
update_install_started,
|
||||||
|
op,
|
||||||
|
"st",
|
||||||
|
op->acquired_version,
|
||||||
|
0LU);
|
||||||
|
if (r < 0)
|
||||||
|
return log_bus_error(r, NULL, op->target_id, "call Install");
|
||||||
|
TAKE_PTR(op);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int update_interrupted(sd_event_source *source, void *userdata) {
|
static int update_interrupted(sd_event_source *source, void *userdata) {
|
||||||
/* Since the event loop is exiting, we will never receive the JobRemoved
|
/* Since the event loop is exiting, we will never receive the JobRemoved
|
||||||
* signal. So, we must free the userdata here. */
|
* signal. So, we must free the userdata here. */
|
||||||
@ -959,6 +1085,8 @@ static int update_interrupted(sd_event_source *source, void *userdata) {
|
|||||||
OrderedHashmap *map = ASSERT_PTR(op->userdata);
|
OrderedHashmap *map = ASSERT_PTR(op->userdata);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
/* This call should work regardless of whether we’re cancelling the Acquire() call or the Install()
|
||||||
|
* call. */
|
||||||
r = sd_bus_call_method(op->bus,
|
r = sd_bus_call_method(op->bus,
|
||||||
bus_sysupdate_mgr->destination,
|
bus_sysupdate_mgr->destination,
|
||||||
op->job_path,
|
op->job_path,
|
||||||
@ -977,7 +1105,7 @@ static int update_interrupted(sd_event_source *source, void *userdata) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int update_started(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
|
static int update_acquire_started(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
|
||||||
_cleanup_(operation_freep) Operation *op = ASSERT_PTR(userdata);
|
_cleanup_(operation_freep) Operation *op = ASSERT_PTR(userdata);
|
||||||
OrderedHashmap *map = ASSERT_PTR(op->userdata);
|
OrderedHashmap *map = ASSERT_PTR(op->userdata);
|
||||||
const sd_bus_error *e;
|
const sd_bus_error *e;
|
||||||
@ -1008,6 +1136,12 @@ static int update_started(sd_bus_message *reply, void *userdata, sd_bus_error *r
|
|||||||
op->job_path = strdup(job_path);
|
op->job_path = strdup(job_path);
|
||||||
if (!op->job_path)
|
if (!op->job_path)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
/* Store the version for the subsequent Install() call */
|
||||||
|
op->acquired_version = strdup(new_version);
|
||||||
|
if (!op->acquired_version)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
if (isempty(new_version))
|
if (isempty(new_version))
|
||||||
new_version = "latest";
|
new_version = "latest";
|
||||||
|
|
||||||
@ -1047,7 +1181,7 @@ static int update_started(sd_bus_message *reply, void *userdata, sd_bus_error *r
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_bus_error(r, NULL, op->target_id, "listen for PropertiesChanged");
|
return log_bus_error(r, NULL, op->target_id, "listen for PropertiesChanged");
|
||||||
|
|
||||||
TAKE_PTR(op); /* update_finished/update_interrupted take ownership of the data */
|
TAKE_PTR(op); /* update_acquire_finished/update_interrupted take ownership of the data */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1094,7 +1228,7 @@ static int do_update(sd_bus *bus, char **targets) {
|
|||||||
|
|
||||||
/* Sign up for notification when the associated job finishes */
|
/* Sign up for notification when the associated job finishes */
|
||||||
r = bus_match_signal_async(
|
r = bus_match_signal_async(
|
||||||
op->bus, &op->job_finished_slot, bus_sysupdate_mgr, "JobRemoved", update_finished, NULL, op);
|
op->bus, &op->job_finished_slot, bus_sysupdate_mgr, "JobRemoved", update_acquire_finished, NULL, op);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_bus_error(r, NULL, op->target_id, "listen for JobRemoved");
|
return log_bus_error(r, NULL, op->target_id, "listen for JobRemoved");
|
||||||
|
|
||||||
@ -1104,14 +1238,14 @@ static int do_update(sd_bus *bus, char **targets) {
|
|||||||
bus_sysupdate_mgr->destination,
|
bus_sysupdate_mgr->destination,
|
||||||
target_paths[i],
|
target_paths[i],
|
||||||
SYSUPDATE_TARGET_INTERFACE,
|
SYSUPDATE_TARGET_INTERFACE,
|
||||||
"Update",
|
"Acquire",
|
||||||
update_started,
|
update_acquire_started,
|
||||||
op,
|
op,
|
||||||
"st",
|
"st",
|
||||||
versions[i],
|
versions[i],
|
||||||
0LU);
|
0LU);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_bus_error(r, NULL, targets[i], "call Update");
|
return log_bus_error(r, NULL, targets[i], "call Acquire");
|
||||||
TAKE_PTR(op);
|
TAKE_PTR(op);
|
||||||
|
|
||||||
remaining++;
|
remaining++;
|
||||||
|
|||||||
@ -1105,6 +1105,7 @@ TEST(unit_properties) {
|
|||||||
"ConditionPathIsMountPoint=|foo",
|
"ConditionPathIsMountPoint=|foo",
|
||||||
"ConditionPathIsReadWrite=|foo",
|
"ConditionPathIsReadWrite=|foo",
|
||||||
"ConditionPathIsEncrypted=|foo",
|
"ConditionPathIsEncrypted=|foo",
|
||||||
|
"ConditionPathIsSocket=|foo",
|
||||||
"ConditionDirectoryNotEmpty=|foo",
|
"ConditionDirectoryNotEmpty=|foo",
|
||||||
"ConditionFileNotEmpty=|foo",
|
"ConditionFileNotEmpty=|foo",
|
||||||
"ConditionFileIsExecutable=|foo",
|
"ConditionFileIsExecutable=|foo",
|
||||||
@ -1139,6 +1140,7 @@ TEST(unit_properties) {
|
|||||||
"AssertPathIsMountPoint=|foo",
|
"AssertPathIsMountPoint=|foo",
|
||||||
"AssertPathIsReadWrite=|foo",
|
"AssertPathIsReadWrite=|foo",
|
||||||
"AssertPathIsEncrypted=|foo",
|
"AssertPathIsEncrypted=|foo",
|
||||||
|
"AssertPathIsSocket=|foo",
|
||||||
"AssertDirectoryNotEmpty=|foo",
|
"AssertDirectoryNotEmpty=|foo",
|
||||||
"AssertFileNotEmpty=|foo",
|
"AssertFileNotEmpty=|foo",
|
||||||
"AssertFileIsExecutable=|foo",
|
"AssertFileIsExecutable=|foo",
|
||||||
|
|||||||
@ -110,6 +110,16 @@ TEST(condition_test_path) {
|
|||||||
ASSERT_OK_ZERO(condition_test(condition, environ));
|
ASSERT_OK_ZERO(condition_test(condition, environ));
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
|
if (access("/run/dbus/system_bus_socket", F_OK) >= 0) {
|
||||||
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_PATH_IS_SOCKET, "/run/dbus/system_bus_socket", false, false)));
|
||||||
|
ASSERT_OK_POSITIVE(condition_test(condition, environ));
|
||||||
|
condition_free(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_PATH_IS_SOCKET, "/sys", false, false)));
|
||||||
|
ASSERT_OK_ZERO(condition_test(condition, environ));
|
||||||
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_PATH_IS_SYMBOLIC_LINK, "/dev/stdout", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_PATH_IS_SYMBOLIC_LINK, "/dev/stdout", false, false)));
|
||||||
ASSERT_OK_POSITIVE(condition_test(condition, environ));
|
ASSERT_OK_POSITIVE(condition_test(condition, environ));
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
@ -187,15 +197,15 @@ TEST(condition_test_ac_power) {
|
|||||||
Condition *condition;
|
Condition *condition;
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_AC_POWER, "true", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_AC_POWER, "true", false, false)));
|
||||||
assert_se(condition_test(condition, environ) == on_ac_power());
|
ASSERT_OK_EQ(condition_test(condition, environ), on_ac_power());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_AC_POWER, "false", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_AC_POWER, "false", false, false)));
|
||||||
assert_se(condition_test(condition, environ) != on_ac_power());
|
ASSERT_OK_NE(condition_test(condition, environ), on_ac_power());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_AC_POWER, "false", false, true)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_AC_POWER, "false", false, true)));
|
||||||
assert_se(condition_test(condition, environ) == on_ac_power());
|
ASSERT_OK_EQ(condition_test(condition, environ), on_ac_power());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,8 +724,8 @@ TEST(condition_test_credential) {
|
|||||||
_cleanup_free_ char *d1 = NULL, *d2 = NULL, *j = NULL;
|
_cleanup_free_ char *d1 = NULL, *d2 = NULL, *j = NULL;
|
||||||
Condition *condition;
|
Condition *condition;
|
||||||
|
|
||||||
assert_se(free_and_strdup(&d1, getenv("CREDENTIALS_DIRECTORY")) >= 0);
|
ASSERT_OK(free_and_strdup(&d1, getenv("CREDENTIALS_DIRECTORY")));
|
||||||
assert_se(free_and_strdup(&d2, getenv("ENCRYPTED_CREDENTIALS_DIRECTORY")) >= 0);
|
ASSERT_OK(free_and_strdup(&d2, getenv("ENCRYPTED_CREDENTIALS_DIRECTORY")));
|
||||||
|
|
||||||
ASSERT_OK_ERRNO(unsetenv("CREDENTIALS_DIRECTORY"));
|
ASSERT_OK_ERRNO(unsetenv("CREDENTIALS_DIRECTORY"));
|
||||||
ASSERT_OK_ERRNO(unsetenv("ENCRYPTED_CREDENTIALS_DIRECTORY"));
|
ASSERT_OK_ERRNO(unsetenv("ENCRYPTED_CREDENTIALS_DIRECTORY"));
|
||||||
@ -729,8 +739,8 @@ TEST(condition_test_credential) {
|
|||||||
ASSERT_OK_ZERO(condition_test(condition, environ));
|
ASSERT_OK_ZERO(condition_test(condition, environ));
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
assert_se(mkdtemp_malloc(NULL, &n1) >= 0);
|
ASSERT_OK(mkdtemp_malloc(NULL, &n1));
|
||||||
assert_se(mkdtemp_malloc(NULL, &n2) >= 0);
|
ASSERT_OK(mkdtemp_malloc(NULL, &n2));
|
||||||
|
|
||||||
ASSERT_OK_ERRNO(setenv("CREDENTIALS_DIRECTORY", n1, /* overwrite= */ true));
|
ASSERT_OK_ERRNO(setenv("CREDENTIALS_DIRECTORY", n1, /* overwrite= */ true));
|
||||||
ASSERT_OK_ERRNO(setenv("ENCRYPTED_CREDENTIALS_DIRECTORY", n2, /* overwrite= */ true));
|
ASSERT_OK_ERRNO(setenv("ENCRYPTED_CREDENTIALS_DIRECTORY", n2, /* overwrite= */ true));
|
||||||
@ -740,20 +750,20 @@ TEST(condition_test_credential) {
|
|||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((j = path_join(n1, "existing")));
|
ASSERT_NOT_NULL((j = path_join(n1, "existing")));
|
||||||
assert_se(touch(j) >= 0);
|
ASSERT_OK(touch(j));
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_CREDENTIAL, "existing", /* trigger= */ false, /* negate= */ false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_CREDENTIAL, "existing", /* trigger= */ false, /* negate= */ false)));
|
||||||
ASSERT_OK_POSITIVE(condition_test(condition, environ));
|
ASSERT_OK_POSITIVE(condition_test(condition, environ));
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
free(j);
|
free(j);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((j = path_join(n2, "existing-encrypted")));
|
ASSERT_NOT_NULL((j = path_join(n2, "existing-encrypted")));
|
||||||
assert_se(touch(j) >= 0);
|
ASSERT_OK(touch(j));
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_CREDENTIAL, "existing-encrypted", /* trigger= */ false, /* negate= */ false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_CREDENTIAL, "existing-encrypted", /* trigger= */ false, /* negate= */ false)));
|
||||||
ASSERT_OK_POSITIVE(condition_test(condition, environ));
|
ASSERT_OK_POSITIVE(condition_test(condition, environ));
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
assert_se(set_unset_env("CREDENTIALS_DIRECTORY", d1, /* overwrite= */ true) >= 0);
|
ASSERT_OK(set_unset_env("CREDENTIALS_DIRECTORY", d1, /* overwrite= */ true));
|
||||||
assert_se(set_unset_env("ENCRYPTED_CREDENTIALS_DIRECTORY", d2, /* overwrite= */ true) >= 0);
|
ASSERT_OK(set_unset_env("ENCRYPTED_CREDENTIALS_DIRECTORY", d2, /* overwrite= */ true));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
@ -782,35 +792,35 @@ TEST(condition_test_security) {
|
|||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "selinux", false, true)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "selinux", false, true)));
|
||||||
assert_se(condition_test(condition, environ) != mac_selinux_use());
|
ASSERT_OK_NE(condition_test(condition, environ), mac_selinux_use());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "apparmor", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "apparmor", false, false)));
|
||||||
assert_se(condition_test(condition, environ) == mac_apparmor_use());
|
ASSERT_OK_EQ(condition_test(condition, environ), mac_apparmor_use());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "tomoyo", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "tomoyo", false, false)));
|
||||||
assert_se(condition_test(condition, environ) == mac_tomoyo_use());
|
ASSERT_OK_EQ(condition_test(condition, environ), mac_tomoyo_use());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "ima", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "ima", false, false)));
|
||||||
assert_se(condition_test(condition, environ) == use_ima());
|
ASSERT_OK_EQ(condition_test(condition, environ), use_ima());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "smack", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "smack", false, false)));
|
||||||
assert_se(condition_test(condition, environ) == mac_smack_use());
|
ASSERT_OK_EQ(condition_test(condition, environ), mac_smack_use());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "audit", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "audit", false, false)));
|
||||||
assert_se(condition_test(condition, environ) == use_audit());
|
ASSERT_OK_EQ(condition_test(condition, environ), use_audit());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "uefi-secureboot", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "uefi-secureboot", false, false)));
|
||||||
assert_se(condition_test(condition, environ) == is_efi_secure_boot());
|
ASSERT_OK_EQ(condition_test(condition, environ), is_efi_secure_boot());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "cvm", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_SECURITY, "cvm", false, false)));
|
||||||
assert_se(condition_test(condition, environ) ==
|
ASSERT_OK_EQ(condition_test(condition, environ),
|
||||||
(detect_confidential_virtualization() != CONFIDENTIAL_VIRTUALIZATION_NONE));
|
(detect_confidential_virtualization() != CONFIDENTIAL_VIRTUALIZATION_NONE));
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
}
|
}
|
||||||
@ -844,19 +854,19 @@ TEST(condition_test_virtualization) {
|
|||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_VIRTUALIZATION, "container", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_VIRTUALIZATION, "container", false, false)));
|
||||||
r = condition_test(condition, environ);
|
r = condition_test(condition, environ);
|
||||||
log_info("ConditionVirtualization=container → %i", r);
|
log_info("ConditionVirtualization=container → %i", r);
|
||||||
assert_se(r == !!detect_container());
|
ASSERT_OK_EQ(r, !!detect_container());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_VIRTUALIZATION, "vm", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_VIRTUALIZATION, "vm", false, false)));
|
||||||
r = condition_test(condition, environ);
|
r = condition_test(condition, environ);
|
||||||
log_info("ConditionVirtualization=vm → %i", r);
|
log_info("ConditionVirtualization=vm → %i", r);
|
||||||
assert_se(r == (detect_vm() && !detect_container()));
|
ASSERT_OK_EQ(r, (detect_vm() && !detect_container()));
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_VIRTUALIZATION, "private-users", false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_VIRTUALIZATION, "private-users", false, false)));
|
||||||
r = condition_test(condition, environ);
|
r = condition_test(condition, environ);
|
||||||
log_info("ConditionVirtualization=private-users → %i", r);
|
log_info("ConditionVirtualization=private-users → %i", r);
|
||||||
assert_se(r == !!running_in_userns());
|
ASSERT_OK_EQ(r, !!running_in_userns());
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
NULSTR_FOREACH(virt,
|
NULSTR_FOREACH(virt,
|
||||||
@ -963,13 +973,12 @@ TEST(condition_test_group) {
|
|||||||
ASSERT_OK_POSITIVE(r);
|
ASSERT_OK_POSITIVE(r);
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
ngroups_max = sysconf(_SC_NGROUPS_MAX);
|
ngroups_max = ASSERT_OK_ERRNO(sysconf(_SC_NGROUPS_MAX));
|
||||||
assert_se(ngroups_max > 0);
|
ASSERT_GT(ngroups_max, 0);
|
||||||
|
|
||||||
gids = newa(gid_t, ngroups_max);
|
gids = newa(gid_t, ngroups_max);
|
||||||
|
|
||||||
ngroups = getgroups(ngroups_max, gids);
|
ngroups = ASSERT_OK_ERRNO(getgroups(ngroups_max, gids));
|
||||||
assert_se(ngroups >= 0);
|
|
||||||
|
|
||||||
max_gid = getgid();
|
max_gid = getgid();
|
||||||
for (i = 0; i < ngroups; i++) {
|
for (i = 0; i < ngroups; i++) {
|
||||||
@ -1019,15 +1028,12 @@ TEST(condition_test_group) {
|
|||||||
|
|
||||||
static void test_condition_test_cpus_one(const char *s, bool result) {
|
static void test_condition_test_cpus_one(const char *s, bool result) {
|
||||||
Condition *condition;
|
Condition *condition;
|
||||||
int r;
|
|
||||||
|
|
||||||
log_debug("%s=%s", condition_type_to_string(CONDITION_CPUS), s);
|
log_debug("%s=%s", condition_type_to_string(CONDITION_CPUS), s);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPUS, s, false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPUS, s, false, false)));
|
||||||
|
|
||||||
r = condition_test(condition, environ);
|
ASSERT_OK_EQ(condition_test(condition, environ), result);
|
||||||
assert_se(r >= 0);
|
|
||||||
assert_se(r == result);
|
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1035,8 +1041,7 @@ TEST(condition_test_cpus) {
|
|||||||
_cleanup_free_ char *t = NULL;
|
_cleanup_free_ char *t = NULL;
|
||||||
int cpus;
|
int cpus;
|
||||||
|
|
||||||
cpus = cpus_in_affinity_mask();
|
cpus = ASSERT_OK(cpus_in_affinity_mask());
|
||||||
assert_se(cpus >= 0);
|
|
||||||
|
|
||||||
test_condition_test_cpus_one("> 0", true);
|
test_condition_test_cpus_one("> 0", true);
|
||||||
test_condition_test_cpus_one(">= 0", true);
|
test_condition_test_cpus_one(">= 0", true);
|
||||||
@ -1052,42 +1057,39 @@ TEST(condition_test_cpus) {
|
|||||||
test_condition_test_cpus_one("!= 100000", true);
|
test_condition_test_cpus_one("!= 100000", true);
|
||||||
test_condition_test_cpus_one("<= 100000", true);
|
test_condition_test_cpus_one("<= 100000", true);
|
||||||
|
|
||||||
assert_se(asprintf(&t, "= %i", cpus) >= 0);
|
ASSERT_OK(asprintf(&t, "= %i", cpus));
|
||||||
test_condition_test_cpus_one(t, true);
|
test_condition_test_cpus_one(t, true);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
|
|
||||||
assert_se(asprintf(&t, "<= %i", cpus) >= 0);
|
ASSERT_OK(asprintf(&t, "<= %i", cpus));
|
||||||
test_condition_test_cpus_one(t, true);
|
test_condition_test_cpus_one(t, true);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
|
|
||||||
assert_se(asprintf(&t, ">= %i", cpus) >= 0);
|
ASSERT_OK(asprintf(&t, ">= %i", cpus));
|
||||||
test_condition_test_cpus_one(t, true);
|
test_condition_test_cpus_one(t, true);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
|
|
||||||
assert_se(asprintf(&t, "!= %i", cpus) >= 0);
|
ASSERT_OK(asprintf(&t, "!= %i", cpus));
|
||||||
test_condition_test_cpus_one(t, false);
|
test_condition_test_cpus_one(t, false);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
|
|
||||||
assert_se(asprintf(&t, "< %i", cpus) >= 0);
|
ASSERT_OK(asprintf(&t, "< %i", cpus));
|
||||||
test_condition_test_cpus_one(t, false);
|
test_condition_test_cpus_one(t, false);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
|
|
||||||
assert_se(asprintf(&t, "> %i", cpus) >= 0);
|
ASSERT_OK(asprintf(&t, "> %i", cpus));
|
||||||
test_condition_test_cpus_one(t, false);
|
test_condition_test_cpus_one(t, false);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_condition_test_memory_one(const char *s, bool result) {
|
static void test_condition_test_memory_one(const char *s, bool result) {
|
||||||
Condition *condition;
|
Condition *condition;
|
||||||
int r;
|
|
||||||
|
|
||||||
log_debug("%s=%s", condition_type_to_string(CONDITION_MEMORY), s);
|
log_debug("%s=%s", condition_type_to_string(CONDITION_MEMORY), s);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_MEMORY, s, false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_MEMORY, s, false, false)));
|
||||||
|
|
||||||
r = condition_test(condition, environ);
|
ASSERT_OK_EQ(condition_test(condition, environ), result);
|
||||||
assert_se(r >= 0);
|
|
||||||
assert_se(r == result);
|
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1132,42 +1134,39 @@ TEST(condition_test_memory) {
|
|||||||
test_condition_test_memory_one("!= 100 T 1 G", true);
|
test_condition_test_memory_one("!= 100 T 1 G", true);
|
||||||
test_condition_test_memory_one("<= 100 T 1 G", true);
|
test_condition_test_memory_one("<= 100 T 1 G", true);
|
||||||
|
|
||||||
assert_se(asprintf(&t, "= %" PRIu64, memory) >= 0);
|
ASSERT_OK(asprintf(&t, "= %" PRIu64, memory));
|
||||||
test_condition_test_memory_one(t, true);
|
test_condition_test_memory_one(t, true);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
|
|
||||||
assert_se(asprintf(&t, "<= %" PRIu64, memory) >= 0);
|
ASSERT_OK(asprintf(&t, "<= %" PRIu64, memory));
|
||||||
test_condition_test_memory_one(t, true);
|
test_condition_test_memory_one(t, true);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
|
|
||||||
assert_se(asprintf(&t, ">= %" PRIu64, memory) >= 0);
|
ASSERT_OK(asprintf(&t, ">= %" PRIu64, memory));
|
||||||
test_condition_test_memory_one(t, true);
|
test_condition_test_memory_one(t, true);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
|
|
||||||
assert_se(asprintf(&t, "!= %" PRIu64, memory) >= 0);
|
ASSERT_OK(asprintf(&t, "!= %" PRIu64, memory));
|
||||||
test_condition_test_memory_one(t, false);
|
test_condition_test_memory_one(t, false);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
|
|
||||||
assert_se(asprintf(&t, "< %" PRIu64, memory) >= 0);
|
ASSERT_OK(asprintf(&t, "< %" PRIu64, memory));
|
||||||
test_condition_test_memory_one(t, false);
|
test_condition_test_memory_one(t, false);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
|
|
||||||
assert_se(asprintf(&t, "> %" PRIu64, memory) >= 0);
|
ASSERT_OK(asprintf(&t, "> %" PRIu64, memory));
|
||||||
test_condition_test_memory_one(t, false);
|
test_condition_test_memory_one(t, false);
|
||||||
t = mfree(t);
|
t = mfree(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_condition_test_environment_one(const char *s, bool result) {
|
static void test_condition_test_environment_one(const char *s, bool result) {
|
||||||
Condition *condition;
|
Condition *condition;
|
||||||
int r;
|
|
||||||
|
|
||||||
log_debug("%s=%s", condition_type_to_string(CONDITION_ENVIRONMENT), s);
|
log_debug("%s=%s", condition_type_to_string(CONDITION_ENVIRONMENT), s);
|
||||||
|
|
||||||
ASSERT_NOT_NULL((condition = condition_new(CONDITION_ENVIRONMENT, s, false, false)));
|
ASSERT_NOT_NULL((condition = condition_new(CONDITION_ENVIRONMENT, s, false, false)));
|
||||||
|
|
||||||
r = condition_test(condition, environ);
|
ASSERT_OK_EQ(condition_test(condition, environ), result);
|
||||||
assert_se(r >= 0);
|
|
||||||
assert_se(r == result);
|
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1463,13 +1462,11 @@ TEST(condition_test_kernel_module_loaded) {
|
|||||||
Condition *condition;
|
Condition *condition;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
condition = condition_new(CONDITION_KERNEL_MODULE_LOADED, "", /* trigger= */ false, /* negate= */ false);
|
condition = ASSERT_NOT_NULL(condition_new(CONDITION_KERNEL_MODULE_LOADED, "", /* trigger= */ false, /* negate= */ false));
|
||||||
assert_se(condition);
|
|
||||||
ASSERT_OK_ZERO(condition_test(condition, environ));
|
ASSERT_OK_ZERO(condition_test(condition, environ));
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
condition = condition_new(CONDITION_KERNEL_MODULE_LOADED, "..", /* trigger= */ false, /* negate= */ false);
|
condition = ASSERT_NOT_NULL(condition_new(CONDITION_KERNEL_MODULE_LOADED, "..", /* trigger= */ false, /* negate= */ false));
|
||||||
assert_se(condition);
|
|
||||||
ASSERT_OK_ZERO(condition_test(condition, environ));
|
ASSERT_OK_ZERO(condition_test(condition, environ));
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
|
|
||||||
@ -1477,8 +1474,7 @@ TEST(condition_test_kernel_module_loaded) {
|
|||||||
return (void) log_tests_skipped("/sys/module not available, skipping.");
|
return (void) log_tests_skipped("/sys/module not available, skipping.");
|
||||||
|
|
||||||
FOREACH_STRING(m, "random", "vfat", "fat", "cec", "binfmt_misc", "binfmt-misc") {
|
FOREACH_STRING(m, "random", "vfat", "fat", "cec", "binfmt_misc", "binfmt-misc") {
|
||||||
condition = condition_new(CONDITION_KERNEL_MODULE_LOADED, m, /* trigger= */ false, /* negate= */ false);
|
condition = ASSERT_NOT_NULL(condition_new(CONDITION_KERNEL_MODULE_LOADED, m, /* trigger= */ false, /* negate= */ false));
|
||||||
assert_se(condition);
|
|
||||||
r = condition_test(condition, environ);
|
r = condition_test(condition, environ);
|
||||||
ASSERT_OK(r);
|
ASSERT_OK(r);
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
@ -1486,8 +1482,7 @@ TEST(condition_test_kernel_module_loaded) {
|
|||||||
log_notice("kmod %s is loaded: %s", m, yes_no(r));
|
log_notice("kmod %s is loaded: %s", m, yes_no(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
condition = condition_new(CONDITION_KERNEL_MODULE_LOADED, "idefinitelydontexist", /* trigger= */ false, /* negate= */ false);
|
condition = ASSERT_NOT_NULL(condition_new(CONDITION_KERNEL_MODULE_LOADED, "idefinitelydontexist", /* trigger= */ false, /* negate= */ false));
|
||||||
assert_se(condition);
|
|
||||||
ASSERT_OK_ZERO(condition_test(condition, environ));
|
ASSERT_OK_ZERO(condition_test(condition, environ));
|
||||||
condition_free(condition);
|
condition_free(condition);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -270,6 +270,20 @@ static int dump_event_json(UdevEvent *event, sd_json_format_flags_t flags, FILE
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tags = strv_free(tags);
|
||||||
|
|
||||||
|
FOREACH_DEVICE_CURRENT_TAG(dev, tag) {
|
||||||
|
r = strv_extend(&tags, tag);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strv_isempty(tags)) {
|
||||||
|
r = sd_json_variant_set_field_strv(&v, "currentTags", strv_sort(tags));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
char **properties;
|
char **properties;
|
||||||
if (device_get_properties_strv(dev, &properties) >= 0 && !strv_isempty(properties)) {
|
if (device_get_properties_strv(dev, &properties) >= 0 && !strv_isempty(properties)) {
|
||||||
r = sd_json_variant_set_field_strv(&v, "properties", strv_sort(properties));
|
r = sd_json_variant_set_field_strv(&v, "properties", strv_sort(properties));
|
||||||
@ -417,6 +431,12 @@ int dump_event(UdevEvent *event, sd_json_format_flags_t flags, FILE *f) {
|
|||||||
fprintf(f, " %s\n", tag);
|
fprintf(f, " %s\n", tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sd_device_get_current_tag_first(dev)) {
|
||||||
|
fprintf(f, "%sCurrent Tags:%s\n", ansi_highlight(), ansi_normal());
|
||||||
|
FOREACH_DEVICE_CURRENT_TAG(dev, tag)
|
||||||
|
fprintf(f, " %s\n", tag);
|
||||||
|
}
|
||||||
|
|
||||||
char **properties;
|
char **properties;
|
||||||
if (device_get_properties_strv(dev, &properties) >= 0 && !strv_isempty(properties)) {
|
if (device_get_properties_strv(dev, &properties) >= 0 && !strv_isempty(properties)) {
|
||||||
bool space = true;
|
bool space = true;
|
||||||
|
|||||||
@ -63,7 +63,7 @@ int device_broadcast_on_error(sd_device *dev, sd_device_monitor *monitor) {
|
|||||||
|
|
||||||
/* delete state from disk */
|
/* delete state from disk */
|
||||||
(void) device_delete_db(dev);
|
(void) device_delete_db(dev);
|
||||||
(void) device_tag_index(dev, /* device_old= */ NULL, /* add= */ false);
|
(void) device_tag_index(dev, /* add= */ false);
|
||||||
|
|
||||||
r = device_monitor_send(monitor, /* destination= */ NULL, dev);
|
r = device_monitor_send(monitor, /* destination= */ NULL, dev);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
|||||||
@ -310,7 +310,7 @@ static int event_execute_rules_on_remove(UdevEvent *event, UdevRules *rules) {
|
|||||||
log_device_debug_errno(dev, r, "Failed to read database under /run/udev/data/: %m");
|
log_device_debug_errno(dev, r, "Failed to read database under /run/udev/data/: %m");
|
||||||
|
|
||||||
if (EVENT_MODE_DESTRUCTIVE(event)) {
|
if (EVENT_MODE_DESTRUCTIVE(event)) {
|
||||||
r = device_tag_index(dev, NULL, false);
|
r = device_tag_index(dev, /* add= */ false);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_device_debug_errno(dev, r, "Failed to remove corresponding tag files under /run/udev/tag/, ignoring: %m");
|
log_device_debug_errno(dev, r, "Failed to remove corresponding tag files under /run/udev/tag/, ignoring: %m");
|
||||||
|
|
||||||
@ -329,23 +329,6 @@ static int event_execute_rules_on_remove(UdevEvent *event, UdevRules *rules) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copy_all_tags(sd_device *d, sd_device *s) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(d);
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
FOREACH_DEVICE_TAG(s, tag) {
|
|
||||||
r = device_add_tag(d, tag, false);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int update_clone(UdevEvent *event) {
|
static int update_clone(UdevEvent *event) {
|
||||||
sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev_db_clone);
|
sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev_db_clone);
|
||||||
int r;
|
int r;
|
||||||
@ -398,7 +381,7 @@ int udev_event_execute_rules(UdevEvent *event, UdevRules *rules) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_device_debug_errno(dev, r, "Failed to clone sd_device object: %m");
|
return log_device_debug_errno(dev, r, "Failed to clone sd_device object: %m");
|
||||||
|
|
||||||
r = copy_all_tags(dev, event->dev_db_clone);
|
r = device_copy_all_tags(dev, event->dev_db_clone);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_device_warning_errno(dev, r, "Failed to copy all tags from old database entry, ignoring: %m");
|
log_device_warning_errno(dev, r, "Failed to copy all tags from old database entry, ignoring: %m");
|
||||||
|
|
||||||
@ -433,7 +416,7 @@ int udev_event_execute_rules(UdevEvent *event, UdevRules *rules) {
|
|||||||
|
|
||||||
if (EVENT_MODE_DESTRUCTIVE(event)) {
|
if (EVENT_MODE_DESTRUCTIVE(event)) {
|
||||||
/* (re)write database file */
|
/* (re)write database file */
|
||||||
r = device_tag_index(dev, event->dev_db_clone, true);
|
r = device_tag_index(dev, /* add= */ true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_device_debug_errno(dev, r, "Failed to update tags under /run/udev/tag/: %m");
|
return log_device_debug_errno(dev, r, "Failed to update tags under /run/udev/tag/: %m");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2900,8 +2900,11 @@ static int udev_rule_apply_token_to_event(
|
|||||||
|
|
||||||
assert(IN_SET(token->op, OP_ASSIGN, OP_ADD));
|
assert(IN_SET(token->op, OP_ASSIGN, OP_ADD));
|
||||||
|
|
||||||
if (token->op == OP_ASSIGN)
|
if (token->op == OP_ASSIGN) {
|
||||||
device_cleanup_tags(dev);
|
r = device_cleanup_tags(dev, event->dev_db_clone);
|
||||||
|
if (r < 0)
|
||||||
|
log_event_warning_errno(event, token, r, "Failed to clear previously assigned tags, ignoring: %m");
|
||||||
|
}
|
||||||
|
|
||||||
r = device_add_tag(dev, buf, /* both= */ true);
|
r = device_add_tag(dev, buf, /* both= */ true);
|
||||||
if (r == -ENOMEM)
|
if (r == -ENOMEM)
|
||||||
|
|||||||
@ -6,4 +6,3 @@
|
|||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
|
|
||||||
g systemd-journal {{SYSTEMD_JOURNAL_GID}} -
|
g systemd-journal {{SYSTEMD_JOURNAL_GID}} -
|
||||||
u! systemd-journal {{SYSTEMD_JOURNAL_UID}} "systemd Journal"
|
|
||||||
|
|||||||
@ -21,6 +21,8 @@ if [[ ! -x "$SYSUPDATE" ]]; then
|
|||||||
exit 77
|
exit 77
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
have_updatectl=$([[ -x "$SYSUPDATED" ]] && command -v updatectl)
|
||||||
|
|
||||||
# Loopback devices may not be supported. They are used because sfdisk cannot
|
# Loopback devices may not be supported. They are used because sfdisk cannot
|
||||||
# change the sector size of a file, and we want to test both 512 and 4096 byte
|
# change the sector size of a file, and we want to test both 512 and 4096 byte
|
||||||
# sectors. If loopback devices are not supported, we can only test one sector
|
# sectors. If loopback devices are not supported, we can only test one sector
|
||||||
@ -112,6 +114,16 @@ update_now() {
|
|||||||
elif [[ "$update_type" == "split" ]]; then
|
elif [[ "$update_type" == "split" ]]; then
|
||||||
"$SYSUPDATE" --verify=no acquire
|
"$SYSUPDATE" --verify=no acquire
|
||||||
"$SYSUPDATE" --verify=no update
|
"$SYSUPDATE" --verify=no update
|
||||||
|
elif [[ "$update_type" == "updatectl" ]]; then
|
||||||
|
if $have_updatectl; then
|
||||||
|
systemctl start systemd-sysupdated
|
||||||
|
updatectl update
|
||||||
|
else
|
||||||
|
# Gracefully fall back to sysupdate
|
||||||
|
"$SYSUPDATE" --verify=no update
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
(! "$SYSUPDATE" --verify=no check-new)
|
(! "$SYSUPDATE" --verify=no check-new)
|
||||||
}
|
}
|
||||||
@ -150,8 +162,14 @@ verify_version_current() {
|
|||||||
cmp "$WORKDIR/source/dir-$version/bar.txt" "$WORKDIR/dirs/current/bar.txt"
|
cmp "$WORKDIR/source/dir-$version/bar.txt" "$WORKDIR/dirs/current/bar.txt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
verify_object_fields() {
|
||||||
|
local updatectl_output="${1:?}"
|
||||||
|
|
||||||
|
[[ "${updatectl_output}" != *"Unrecognized object field"* ]] || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
for sector_size in "${SECTOR_SIZES[@]}"; do
|
for sector_size in "${SECTOR_SIZES[@]}"; do
|
||||||
for update_type in monolithic split-offline split; do
|
for update_type in monolithic split-offline split updatectl; do
|
||||||
# Disk size of:
|
# Disk size of:
|
||||||
# - 1MB for GPT
|
# - 1MB for GPT
|
||||||
# - 4 partitions of 2048 sectors each
|
# - 4 partitions of 2048 sectors each
|
||||||
@ -352,7 +370,7 @@ EOF
|
|||||||
# Create sixth version, update using updatectl and verify it replaced the
|
# Create sixth version, update using updatectl and verify it replaced the
|
||||||
# correct version
|
# correct version
|
||||||
new_version "$sector_size" v6
|
new_version "$sector_size" v6
|
||||||
if [[ -x "$SYSUPDATED" ]] && command -v updatectl; then
|
if $have_updatectl; then
|
||||||
systemctl start systemd-sysupdated
|
systemctl start systemd-sysupdated
|
||||||
"$SYSUPDATE" --verify=no check-new
|
"$SYSUPDATE" --verify=no check-new
|
||||||
updatectl update
|
updatectl update
|
||||||
@ -370,12 +388,12 @@ EOF
|
|||||||
# testing for specific output, but this will at least catch obvious crashes
|
# testing for specific output, but this will at least catch obvious crashes
|
||||||
# and allow updatectl to run under the various sanitizers. We create a
|
# and allow updatectl to run under the various sanitizers. We create a
|
||||||
# component so that updatectl has multiple targets to list.
|
# component so that updatectl has multiple targets to list.
|
||||||
if [[ -x "$SYSUPDATED" ]] && command -v updatectl; then
|
if $have_updatectl; then
|
||||||
mkdir -p /run/sysupdate.test.d/
|
mkdir -p /run/sysupdate.test.d/
|
||||||
cp "$CONFIGDIR/01-first.transfer" /run/sysupdate.test.d/01-first.transfer
|
cp "$CONFIGDIR/01-first.transfer" /run/sysupdate.test.d/01-first.transfer
|
||||||
updatectl list
|
verify_object_fields "$(updatectl list 2>&1)"
|
||||||
updatectl list host
|
verify_object_fields "$(updatectl list host 2>&1)"
|
||||||
updatectl list host@v6
|
verify_object_fields "$(updatectl list host@v6 2>&1)"
|
||||||
updatectl check
|
updatectl check
|
||||||
rm -r /run/sysupdate.test.d
|
rm -r /run/sysupdate.test.d
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -13,7 +13,10 @@ Documentation=man:journalctl(1)
|
|||||||
DefaultDependencies=no
|
DefaultDependencies=no
|
||||||
Conflicts=shutdown.target
|
Conflicts=shutdown.target
|
||||||
Before=shutdown.target
|
Before=shutdown.target
|
||||||
|
RequiresMountsFor=/var/log/journal
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=journalctl
|
ExecStart=journalctl --system
|
||||||
User=systemd-journal
|
DynamicUser=yes
|
||||||
|
User=systemd-journal-access
|
||||||
|
SupplementaryGroups=systemd-journal
|
||||||
|
|||||||
@ -22,6 +22,3 @@ FileDescriptorName=varlink
|
|||||||
SocketMode=0600
|
SocketMode=0600
|
||||||
Accept=yes
|
Accept=yes
|
||||||
MaxConnectionsPerSource=16
|
MaxConnectionsPerSource=16
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=sockets.target
|
|
||||||
|
|||||||
@ -17,4 +17,3 @@ Symlinks=%t/varlink/registry/io.systemd.JournalAccess
|
|||||||
FileDescriptorName=varlink
|
FileDescriptorName=varlink
|
||||||
SocketMode=0600
|
SocketMode=0600
|
||||||
Accept=yes
|
Accept=yes
|
||||||
MaxConnectionsPerSource=16
|
|
||||||
|
|||||||
@ -12,4 +12,4 @@ Description=Journal Log Access Service
|
|||||||
Documentation=man:journalctl(1)
|
Documentation=man:journalctl(1)
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=journalctl
|
ExecStart=journalctl --user
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user