1
0
mirror of https://github.com/systemd/systemd synced 2026-02-26 01:04:46 +01:00

Compare commits

..

No commits in common. "61b31f7999107e6a5dbda76049dc37f8061c082c" and "a2a78602b08bcec571fb081bdeb1d8854d91f93e" have entirely different histories.

41 changed files with 502 additions and 756 deletions

9
NEWS
View File

@ -55,14 +55,7 @@ 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
View File

@ -967,6 +967,7 @@ 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

View File

@ -120,12 +120,7 @@ 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);
Acquire(in s new_version, Update(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,
@ -168,9 +163,7 @@ 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="Acquire()"/> <variablelist class="dbus-method" generated="True" extra-ref="Update()"/>
<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()"/>
@ -252,8 +245,7 @@ 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>Acquire()</function> and <function>Install()</function> be repaired in-place by calling <function>Update()</function> on that version.</para></listitem>
on that version.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
@ -269,25 +261,16 @@ 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>Acquire()</function> downloads an update for this target, if one is available. If a <para><function>Update()</function> installs an update for this target. If a
<varname>new_version</varname> is specified, that is the version that gets downloaded. Otherwise, the <varname>new_version</varname> is specified, that is the version that gets installed. Otherwise, the
latest version is downloaded. Call <function>Install()</function> to install the acquired update. latest version is installed. The <varname>flags</varname> argument is added for future
The <varname>flags</varname> argument is added for future extensibility. No flags are currently extensibility. No flags are currently defined, and the argument is required to be set to
defined, and the argument is required to be set to <literal>0</literal>. This method pulls both <literal>0</literal>. Unlike all the other methods in this interface, <function>Update()</function>
metadata and payload data from the network.</para> does not wait for its job to complete. Instead, it returns 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. This
<para><function>Install()</function> installs an already-acquired update for this target. If a method also returns the version the target will be updated to, for cases where no version was specified
<varname>new_version</varname> is specified, that is the version that gets installed, assuming it has by the caller. This method pulls both metadata and payload data from the network. Listen for the
already been acquired. Otherwise, the latest acquired version is installed. The Manager's <function>JobRemoved()</function> signal to detect when the job is complete.</para>
<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>
@ -364,7 +347,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>Acquire()</function> and <function>Install()</function>. call <function>Update()</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>).
@ -414,8 +397,7 @@ 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>Acquire()</function> and <function>Install()</function> <para><function>Update()</function> uses the polkit action
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
@ -514,15 +496,14 @@ 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>acquire</literal>, <literal>install</literal>, <literal>vacuum</literal>, or <literal>update</literal>, <literal>vacuum</literal>, or <literal>describe-feature</literal>).</para>
<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>acquire</literal> and <literal>install</literal> between 0 and 100. It is only available for <literal>update</literal> jobs; for all other jobs
jobs; for all other jobs it is always 0.</para> it is always 0.</para>
</refsect2> </refsect2>
<refsect2> <refsect2>
@ -581,8 +562,7 @@ 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>Acquire()</function>, <function>Update()</function>,
<function>Install()</function>,
<function>Vacuum()</function>, <function>Vacuum()</function>,
<function>GetAppStream()</function>, <function>GetAppStream()</function>,
<function>GetVersion()</function>, <function>GetVersion()</function>,

View File

@ -497,6 +497,17 @@
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
@ -506,9 +517,6 @@
<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>

View File

@ -1797,17 +1797,6 @@
</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>
@ -2063,7 +2052,6 @@
<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>

View File

@ -895,6 +895,7 @@ 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']

View File

@ -328,6 +328,8 @@ 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,

View File

@ -97,7 +97,6 @@ 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;

View File

@ -366,7 +366,6 @@ 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)
@ -402,7 +401,6 @@ 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)

View File

@ -9,7 +9,6 @@
#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"
@ -72,116 +71,6 @@ 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;
@ -193,9 +82,7 @@ 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, return journal_add_unit_matches(j, flags, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, arg_system_units, arg_user_units);
arg_system_units,
UID_INVALID, arg_user_units);
} }
static int add_syslog_identifier(sd_journal *j) { static int add_syslog_identifier(sd_journal *j) {

View File

@ -3,12 +3,4 @@
#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);

View File

@ -177,6 +177,108 @@ 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;

View File

@ -3,6 +3,7 @@
#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(). */
@ -31,5 +32,6 @@ 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);

View File

@ -4,30 +4,25 @@
#include "sd-varlink.h" #include "sd-varlink.h"
#include "journal-internal.h" #include "journal-internal.h"
#include "journalctl.h" #include "journalctl-util.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);
} }
@ -36,7 +31,6 @@ 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 },
@ -45,7 +39,6 @@ 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;
@ -58,26 +51,23 @@ 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 r; return log_error_errno(r, "Failed to open journal: %m");
r = journal_add_unit_matches(j, MATCH_UNIT_ALL, /* mangle_flags= */ 0, p.units, p.uid, p.user_units); r = journal_add_unit_matches(j, MATCH_UNIT_ALL, /* mangle_flags= */ 0, p.units, p.user_units);
if (r == -ENODATA) if (r == -ENODATA)
return sd_varlink_error(link, "io.systemd.JournalAccess.NoMatches", NULL); return sd_varlink_error(link, SD_VARLINK_ERROR_INVALID_PARAMETER, NULL);
if (r < 0) if (r < 0)
return r; return log_error_errno(r, "Failed to add unit matches: %m");
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 r; return log_error_errno(r, "Failed to add priority match: %m");
} }
r = sd_journal_add_conjunction(j); r = sd_journal_add_conjunction(j);
@ -88,7 +78,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 r; return log_error_errno(r, "Failed to seek to tail: %m");
/* FIXME: this restriction should be removed eventually */ /* FIXME: this restriction should be removed eventually */
if (p.limit > 10000) if (p.limit > 10000)
@ -96,10 +86,6 @@ 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;
@ -107,9 +93,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_next(j); r = sd_journal_previous(j);
if (r < 0) if (r < 0)
return r; return log_error_errno(r, "Failed to iterate journal: %m");
if (r == 0) if (r == 0)
break; break;
@ -119,7 +105,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_VARIANT("entry", entry)); r = sd_varlink_replybo(link, SD_JSON_BUILD_PAIR("entry", SD_JSON_BUILD_VARIANT(entry)));
if (r < 0) if (r < 0)
return r; return r;
} }

View File

@ -30,7 +30,6 @@
#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"
@ -112,9 +111,7 @@ 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);
@ -489,35 +486,7 @@ 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;
} }

View File

@ -94,6 +94,3 @@ 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;

View File

@ -693,46 +693,20 @@ int device_clone_with_db(sd_device *device, sd_device **ret) {
return 0; return 0;
} }
int device_copy_all_tags(sd_device *dest, sd_device *src) { void device_cleanup_tags(sd_device *device) {
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);
_cleanup_set_free_ Set *saved = TAKE_PTR(device->all_tags); device->all_tags = set_free(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);
device->devlinks = set_free(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++;
} }
@ -769,9 +743,15 @@ static int device_tag(sd_device *device, const char *tag, bool add) {
return 0; return 0;
} }
int device_tag_index(sd_device *device, bool add) { int device_tag_index(sd_device *device, sd_device *device_old, 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));

View File

@ -45,8 +45,7 @@ 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);
int device_copy_all_tags(sd_device *dest, sd_device *src); void device_cleanup_tags(sd_device *device);
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);
@ -59,7 +58,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, bool add); int device_tag_index(sd_device *device, sd_device *device_old, 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);

View File

@ -992,14 +992,6 @@ 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;
@ -1241,7 +1233,6 @@ 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,
@ -1379,7 +1370,6 @@ 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",
@ -1435,7 +1425,6 @@ 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",

View File

@ -34,7 +34,6 @@ 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,
@ -105,7 +104,6 @@ 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,

View File

@ -1193,20 +1193,17 @@ 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( int journal_entry_to_json(sd_journal *j, OutputFlags flags, const Set *output_fields, sd_json_variant **ret) {
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;
@ -1217,32 +1214,32 @@ int journal_entry_to_json(
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)) {
corrupted_what = "cursor"; log_debug_errno(r, "Unable to determine cursor of entry, assuming bad or partially written entry: %m");
goto corrupted_skip; return 0;
} }
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) {
corrupted_what = "realtime timestamp"; log_debug_errno(r, "Unable to read realtime timestamp of entry, assuming bad or partially written entry: %m");
goto corrupted_skip; return 0;
} }
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) {
corrupted_what = "monotonic timestamp"; log_debug_errno(r, "Unable to read monotonic timestamp of entry, assuming bad or partially written entry: %m");
goto corrupted_skip; return 0;
} }
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) {
corrupted_what = "sequence number"; log_debug_errno(r, "Unable to read sequence number of entry, assuming bad or partially written entry: %m");
goto corrupted_skip; return 0;
} }
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");
@ -1297,32 +1294,29 @@ int journal_entry_to_json(
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();
JsonData *d; CLEANUP_ARRAY(array, n, sd_json_variant_unref_many);
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++] = d->name; array[n++] = sd_json_variant_ref(d->name);
if (sd_json_variant_elements(d->values) == 1) if (sd_json_variant_elements(d->values) == 1)
array[n++] = sd_json_variant_by_index(d->values, 0); array[n++] = sd_json_variant_ref(sd_json_variant_by_index(d->values, 0));
else else
array[n++] = d->values; array[n++] = sd_json_variant_ref(d->values);
} }
r = sd_json_variant_new_object(ret, array, n); r = sd_json_variant_new_object(&object, 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(
@ -1767,15 +1761,13 @@ 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, uid_t uid, const char *unit) { int add_matches_for_user_unit_full(sd_journal *j, MatchUnitFlag flags, 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)) ||
@ -2012,7 +2004,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, UID_INVALID, unit); return add_matches_for_user_unit_full(j, /* flags= */ 0, unit);
return -EINVAL; return -EINVAL;
} }

View File

@ -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, uid_t uid, const char *unit); int add_matches_for_user_unit_full(sd_journal *j, MatchUnitFlag flags, 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, UID_INVALID, unit); return add_matches_for_user_unit_full(j, MATCH_UNIT_ALL, unit);
} }
int show_journal_by_unit( int show_journal_by_unit(

View File

@ -4,6 +4,10 @@
#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"
@ -11,10 +15,12 @@
#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) {
@ -165,6 +171,154 @@ 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,
@ -179,6 +333,8 @@ 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|
@ -404,8 +560,26 @@ 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 && strv_extend_many(&argv, "-p", root) < 0) if (root) {
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)

View File

@ -26,7 +26,6 @@ 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;

View File

@ -274,29 +274,6 @@ _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) \

View File

@ -7,8 +7,6 @@ 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."),
@ -18,9 +16,8 @@ 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, 0)); SD_VARLINK_DEFINE_OUTPUT(entry, SD_VARLINK_OBJECT, SD_VARLINK_NULLABLE));
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(
@ -29,7 +26,5 @@ 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);

View File

@ -64,11 +64,7 @@
<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="Acquire"/> send_member="Update"/>
<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"

View File

@ -100,8 +100,7 @@ typedef enum JobType {
JOB_LIST, JOB_LIST,
JOB_DESCRIBE, JOB_DESCRIBE,
JOB_CHECK_NEW, JOB_CHECK_NEW,
JOB_ACQUIRE, JOB_UPDATE,
JOB_INSTALL,
JOB_VACUUM, JOB_VACUUM,
JOB_DESCRIBE_FEATURE, JOB_DESCRIBE_FEATURE,
_JOB_TYPE_MAX, _JOB_TYPE_MAX,
@ -122,7 +121,7 @@ struct Job {
JobType type; JobType type;
bool offline; bool offline;
char *version; /* Passed into sysupdate for JOB_DESCRIBE, JOB_ACQUIRE and JOB_INSTALL */ char *version; /* Passed into sysupdate for JOB_DESCRIBE and JOB_UPDATE */
char *feature; /* Passed into sysupdate for JOB_DESCRIBE_FEATURE */ char *feature; /* Passed into sysupdate for JOB_DESCRIBE_FEATURE */
unsigned progress_percent; unsigned progress_percent;
@ -154,8 +153,7 @@ 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_ACQUIRE] = "acquire", [JOB_UPDATE] = "update",
[JOB_INSTALL] = "install",
[JOB_VACUUM] = "vacuum", [JOB_VACUUM] = "vacuum",
[JOB_DESCRIBE_FEATURE] = "describe-feature", [JOB_DESCRIBE_FEATURE] = "describe-feature",
}; };
@ -222,11 +220,6 @@ 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;
@ -339,7 +332,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 (job_requires_busy(j)) { if (IN_SET(j->type, JOB_UPDATE, JOB_VACUUM)) {
assert(j->target->busy); assert(j->target->busy);
j->target->busy = false; j->target->busy = false;
} }
@ -437,7 +430,7 @@ static int job_start(Job *j) {
assert(j); assert(j);
if (job_requires_busy(j) && j->target->busy) if (IN_SET(j->type, JOB_UPDATE, JOB_VACUUM) && 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");
@ -460,8 +453,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, acquire, update, vacuum, features */ NULL, /* list, check-new, update, vacuum, features */
NULL, /* maybe version (for list, acquire, update), maybe feature (features) */ NULL, /* maybe version (for list, update), maybe feature (features) */
NULL NULL
}; };
size_t k = 2; size_t k = 2;
@ -486,7 +479,7 @@ static int job_start(Job *j) {
if (target_arg) if (target_arg)
cmd[k++] = target_arg; cmd[k++] = target_arg;
if (j->offline || j->type == JOB_INSTALL) /* install is implemented as `update --offline` */ if (j->offline)
cmd[k++] = "--offline"; cmd[k++] = "--offline";
switch (j->type) { switch (j->type) {
@ -504,13 +497,8 @@ static int job_start(Job *j) {
cmd[k++] = "check-new"; cmd[k++] = "check-new";
break; break;
case JOB_ACQUIRE: case JOB_UPDATE:
cmd[k++] = "acquire"; cmd[k++] = "update";
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;
@ -559,7 +547,7 @@ static int job_start(Job *j) {
j->stdout_fd = TAKE_FD(stdout_fd); j->stdout_fd = TAKE_FD(stdout_fd);
if (job_requires_busy(j)) if (IN_SET(j->type, JOB_UPDATE, JOB_VACUUM))
j->target->busy = true; j->target->busy = true;
return 0; return 0;
@ -593,8 +581,7 @@ 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_ACQUIRE: case JOB_UPDATE:
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
@ -1078,91 +1065,7 @@ static int target_method_check_new(sd_bus_message *msg, void *userdata, sd_bus_e
return 1; return 1;
} }
static int target_method_acquire_finished_early( static int target_method_update_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 acquired. */
return sd_bus_error_setf(error, BUS_ERROR_NO_UPDATE_CANDIDATE,
"Job exited successfully with no work to do, assume already acquired");
}
static int target_method_acquire_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_acquire(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 dont 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_ACQUIRE, t, msg, target_method_acquire_finished_early, &j);
if (r < 0)
return r;
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, sd_bus_message *msg,
const Job *j, const Job *j,
sd_json_variant *json, sd_json_variant *json,
@ -1172,10 +1075,10 @@ static int target_method_install_finished_early(
* 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 installed. */
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 installed"); "Job exited successfully with no work to do, assume already updated");
} }
static int target_method_install_detach(sd_bus_message *msg, const Job *j) { static int target_method_update_detach(sd_bus_message *msg, const Job *j) {
int r; int r;
assert(msg); assert(msg);
@ -1188,7 +1091,7 @@ static int target_method_install_detach(sd_bus_message *msg, const Job *j) {
return 0; return 0;
} }
static int target_method_install(sd_bus_message *msg, void *userdata, sd_bus_error *error) { static int target_method_update(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;
@ -1204,8 +1107,6 @@ static int target_method_install(sd_bus_message *msg, void *userdata, sd_bus_err
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 dont 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
@ -1229,10 +1130,10 @@ static int target_method_install(sd_bus_message *msg, void *userdata, sd_bus_err
if (r == 0) if (r == 0)
return 1; /* Will call us back */ return 1; /* Will call us back */
r = job_new(JOB_INSTALL, t, msg, target_method_install_finished_early, &j); r = job_new(JOB_UPDATE, t, msg, target_method_update_finished_early, &j);
if (r < 0) if (r < 0)
return r; return r;
j->detach_cb = target_method_install_detach; j->detach_cb = target_method_update_detach;
j->version = strdup(version); j->version = strdup(version);
if (!j->version) if (!j->version)
@ -1679,16 +1580,10 @@ 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("Acquire", SD_BUS_METHOD_WITH_ARGS("Update",
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_acquire, target_method_update,
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",

View File

@ -72,9 +72,6 @@ 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) {
@ -89,7 +86,6 @@ 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);
@ -338,8 +334,6 @@ 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;
@ -375,8 +369,6 @@ 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 },
@ -394,8 +386,6 @@ 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);
@ -814,7 +804,6 @@ 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);
@ -864,10 +853,6 @@ 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());
@ -935,60 +920,7 @@ static int update_properties_changed(sd_bus_message *m, void *userdata, sd_bus_e
return 0; return 0;
} }
static int update_install_started(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) { static int update_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);
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;
@ -1019,64 +951,6 @@ static int update_install_finished(sd_bus_message *m, void *userdata, sd_bus_err
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. */
@ -1085,8 +959,6 @@ 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 were 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,
@ -1105,7 +977,7 @@ static int update_interrupted(sd_event_source *source, void *userdata) {
return 0; return 0;
} }
static int update_acquire_started(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) { static int update_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;
@ -1136,12 +1008,6 @@ static int update_acquire_started(sd_bus_message *reply, void *userdata, sd_bus_
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";
@ -1181,7 +1047,7 @@ static int update_acquire_started(sd_bus_message *reply, void *userdata, sd_bus_
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_acquire_finished/update_interrupted take ownership of the data */ TAKE_PTR(op); /* update_finished/update_interrupted take ownership of the data */
return 0; return 0;
} }
@ -1228,7 +1094,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_acquire_finished, NULL, op); op->bus, &op->job_finished_slot, bus_sysupdate_mgr, "JobRemoved", update_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");
@ -1238,14 +1104,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,
"Acquire", "Update",
update_acquire_started, update_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 Acquire"); return log_bus_error(r, NULL, targets[i], "call Update");
TAKE_PTR(op); TAKE_PTR(op);
remaining++; remaining++;

View File

@ -1105,7 +1105,6 @@ 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",
@ -1140,7 +1139,6 @@ 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",

View File

@ -110,16 +110,6 @@ 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);
@ -197,15 +187,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_OK_EQ(condition_test(condition, environ), on_ac_power()); assert_se(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_OK_NE(condition_test(condition, environ), on_ac_power()); assert_se(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_OK_EQ(condition_test(condition, environ), on_ac_power()); assert_se(condition_test(condition, environ) == on_ac_power());
condition_free(condition); condition_free(condition);
} }
@ -724,8 +714,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_OK(free_and_strdup(&d1, getenv("CREDENTIALS_DIRECTORY"))); assert_se(free_and_strdup(&d1, getenv("CREDENTIALS_DIRECTORY")) >= 0);
ASSERT_OK(free_and_strdup(&d2, getenv("ENCRYPTED_CREDENTIALS_DIRECTORY"))); assert_se(free_and_strdup(&d2, getenv("ENCRYPTED_CREDENTIALS_DIRECTORY")) >= 0);
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"));
@ -739,8 +729,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_OK(mkdtemp_malloc(NULL, &n1)); assert_se(mkdtemp_malloc(NULL, &n1) >= 0);
ASSERT_OK(mkdtemp_malloc(NULL, &n2)); assert_se(mkdtemp_malloc(NULL, &n2) >= 0);
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));
@ -750,20 +740,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_OK(touch(j)); assert_se(touch(j) >= 0);
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_OK(touch(j)); assert_se(touch(j) >= 0);
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_OK(set_unset_env("CREDENTIALS_DIRECTORY", d1, /* overwrite= */ true)); assert_se(set_unset_env("CREDENTIALS_DIRECTORY", d1, /* overwrite= */ true) >= 0);
ASSERT_OK(set_unset_env("ENCRYPTED_CREDENTIALS_DIRECTORY", d2, /* overwrite= */ true)); assert_se(set_unset_env("ENCRYPTED_CREDENTIALS_DIRECTORY", d2, /* overwrite= */ true) >= 0);
} }
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
@ -792,35 +782,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_OK_NE(condition_test(condition, environ), mac_selinux_use()); assert_se(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_OK_EQ(condition_test(condition, environ), mac_apparmor_use()); assert_se(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_OK_EQ(condition_test(condition, environ), mac_tomoyo_use()); assert_se(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_OK_EQ(condition_test(condition, environ), use_ima()); assert_se(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_OK_EQ(condition_test(condition, environ), mac_smack_use()); assert_se(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_OK_EQ(condition_test(condition, environ), use_audit()); assert_se(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_OK_EQ(condition_test(condition, environ), is_efi_secure_boot()); assert_se(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_OK_EQ(condition_test(condition, environ), assert_se(condition_test(condition, environ) ==
(detect_confidential_virtualization() != CONFIDENTIAL_VIRTUALIZATION_NONE)); (detect_confidential_virtualization() != CONFIDENTIAL_VIRTUALIZATION_NONE));
condition_free(condition); condition_free(condition);
} }
@ -854,19 +844,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_OK_EQ(r, !!detect_container()); assert_se(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_OK_EQ(r, (detect_vm() && !detect_container())); assert_se(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_OK_EQ(r, !!running_in_userns()); assert_se(r == !!running_in_userns());
condition_free(condition); condition_free(condition);
NULSTR_FOREACH(virt, NULSTR_FOREACH(virt,
@ -973,12 +963,13 @@ TEST(condition_test_group) {
ASSERT_OK_POSITIVE(r); ASSERT_OK_POSITIVE(r);
condition_free(condition); condition_free(condition);
ngroups_max = ASSERT_OK_ERRNO(sysconf(_SC_NGROUPS_MAX)); ngroups_max = sysconf(_SC_NGROUPS_MAX);
ASSERT_GT(ngroups_max, 0); assert_se(ngroups_max > 0);
gids = newa(gid_t, ngroups_max); gids = newa(gid_t, ngroups_max);
ngroups = ASSERT_OK_ERRNO(getgroups(ngroups_max, gids)); ngroups = 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++) {
@ -1028,12 +1019,15 @@ 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)));
ASSERT_OK_EQ(condition_test(condition, environ), result); r = condition_test(condition, environ);
assert_se(r >= 0);
assert_se(r == result);
condition_free(condition); condition_free(condition);
} }
@ -1041,7 +1035,8 @@ TEST(condition_test_cpus) {
_cleanup_free_ char *t = NULL; _cleanup_free_ char *t = NULL;
int cpus; int cpus;
cpus = ASSERT_OK(cpus_in_affinity_mask()); cpus = 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);
@ -1057,39 +1052,42 @@ 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_OK(asprintf(&t, "= %i", cpus)); assert_se(asprintf(&t, "= %i", cpus) >= 0);
test_condition_test_cpus_one(t, true); test_condition_test_cpus_one(t, true);
t = mfree(t); t = mfree(t);
ASSERT_OK(asprintf(&t, "<= %i", cpus)); assert_se(asprintf(&t, "<= %i", cpus) >= 0);
test_condition_test_cpus_one(t, true); test_condition_test_cpus_one(t, true);
t = mfree(t); t = mfree(t);
ASSERT_OK(asprintf(&t, ">= %i", cpus)); assert_se(asprintf(&t, ">= %i", cpus) >= 0);
test_condition_test_cpus_one(t, true); test_condition_test_cpus_one(t, true);
t = mfree(t); t = mfree(t);
ASSERT_OK(asprintf(&t, "!= %i", cpus)); assert_se(asprintf(&t, "!= %i", cpus) >= 0);
test_condition_test_cpus_one(t, false); test_condition_test_cpus_one(t, false);
t = mfree(t); t = mfree(t);
ASSERT_OK(asprintf(&t, "< %i", cpus)); assert_se(asprintf(&t, "< %i", cpus) >= 0);
test_condition_test_cpus_one(t, false); test_condition_test_cpus_one(t, false);
t = mfree(t); t = mfree(t);
ASSERT_OK(asprintf(&t, "> %i", cpus)); assert_se(asprintf(&t, "> %i", cpus) >= 0);
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)));
ASSERT_OK_EQ(condition_test(condition, environ), result); r = condition_test(condition, environ);
assert_se(r >= 0);
assert_se(r == result);
condition_free(condition); condition_free(condition);
} }
@ -1134,39 +1132,42 @@ 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_OK(asprintf(&t, "= %" PRIu64, memory)); assert_se(asprintf(&t, "= %" PRIu64, memory) >= 0);
test_condition_test_memory_one(t, true); test_condition_test_memory_one(t, true);
t = mfree(t); t = mfree(t);
ASSERT_OK(asprintf(&t, "<= %" PRIu64, memory)); assert_se(asprintf(&t, "<= %" PRIu64, memory) >= 0);
test_condition_test_memory_one(t, true); test_condition_test_memory_one(t, true);
t = mfree(t); t = mfree(t);
ASSERT_OK(asprintf(&t, ">= %" PRIu64, memory)); assert_se(asprintf(&t, ">= %" PRIu64, memory) >= 0);
test_condition_test_memory_one(t, true); test_condition_test_memory_one(t, true);
t = mfree(t); t = mfree(t);
ASSERT_OK(asprintf(&t, "!= %" PRIu64, memory)); assert_se(asprintf(&t, "!= %" PRIu64, memory) >= 0);
test_condition_test_memory_one(t, false); test_condition_test_memory_one(t, false);
t = mfree(t); t = mfree(t);
ASSERT_OK(asprintf(&t, "< %" PRIu64, memory)); assert_se(asprintf(&t, "< %" PRIu64, memory) >= 0);
test_condition_test_memory_one(t, false); test_condition_test_memory_one(t, false);
t = mfree(t); t = mfree(t);
ASSERT_OK(asprintf(&t, "> %" PRIu64, memory)); assert_se(asprintf(&t, "> %" PRIu64, memory) >= 0);
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)));
ASSERT_OK_EQ(condition_test(condition, environ), result); r = condition_test(condition, environ);
assert_se(r >= 0);
assert_se(r == result);
condition_free(condition); condition_free(condition);
} }
@ -1462,11 +1463,13 @@ TEST(condition_test_kernel_module_loaded) {
Condition *condition; Condition *condition;
int r; int r;
condition = ASSERT_NOT_NULL(condition_new(CONDITION_KERNEL_MODULE_LOADED, "", /* trigger= */ false, /* negate= */ false)); condition = 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 = ASSERT_NOT_NULL(condition_new(CONDITION_KERNEL_MODULE_LOADED, "..", /* trigger= */ false, /* negate= */ false)); condition = 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);
@ -1474,7 +1477,8 @@ 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 = ASSERT_NOT_NULL(condition_new(CONDITION_KERNEL_MODULE_LOADED, m, /* trigger= */ false, /* negate= */ false)); condition = 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);
@ -1482,7 +1486,8 @@ 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 = ASSERT_NOT_NULL(condition_new(CONDITION_KERNEL_MODULE_LOADED, "idefinitelydontexist", /* trigger= */ false, /* negate= */ false)); condition = 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);
} }

View File

@ -270,20 +270,6 @@ 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));
@ -431,12 +417,6 @@ 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;

View File

@ -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, /* add= */ false); (void) device_tag_index(dev, /* device_old= */ NULL, /* add= */ false);
r = device_monitor_send(monitor, /* destination= */ NULL, dev); r = device_monitor_send(monitor, /* destination= */ NULL, dev);
if (r < 0) { if (r < 0) {

View File

@ -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, /* add= */ false); r = device_tag_index(dev, NULL, 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,6 +329,23 @@ 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;
@ -381,7 +398,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 = device_copy_all_tags(dev, event->dev_db_clone); r = 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");
@ -416,7 +433,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, /* add= */ true); r = device_tag_index(dev, event->dev_db_clone, 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");
} }

View File

@ -2900,11 +2900,8 @@ 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)
r = device_cleanup_tags(dev, event->dev_db_clone); device_cleanup_tags(dev);
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)

View File

@ -6,3 +6,4 @@
# (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"

View File

@ -21,8 +21,6 @@ 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
@ -114,16 +112,6 @@ 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)
} }
@ -162,14 +150,8 @@ 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 updatectl; do for update_type in monolithic split-offline split; 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
@ -370,7 +352,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 $have_updatectl; then if [[ -x "$SYSUPDATED" ]] && command -v updatectl; then
systemctl start systemd-sysupdated systemctl start systemd-sysupdated
"$SYSUPDATE" --verify=no check-new "$SYSUPDATE" --verify=no check-new
updatectl update updatectl update
@ -388,12 +370,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 $have_updatectl; then if [[ -x "$SYSUPDATED" ]] && command -v 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
verify_object_fields "$(updatectl list 2>&1)" updatectl list
verify_object_fields "$(updatectl list host 2>&1)" updatectl list host
verify_object_fields "$(updatectl list host@v6 2>&1)" updatectl list host@v6
updatectl check updatectl check
rm -r /run/sysupdate.test.d rm -r /run/sysupdate.test.d
fi fi

View File

@ -13,10 +13,7 @@ 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 --system ExecStart=journalctl
DynamicUser=yes User=systemd-journal
User=systemd-journal-access
SupplementaryGroups=systemd-journal

View File

@ -22,3 +22,6 @@ FileDescriptorName=varlink
SocketMode=0600 SocketMode=0600
Accept=yes Accept=yes
MaxConnectionsPerSource=16 MaxConnectionsPerSource=16
[Install]
WantedBy=sockets.target

View File

@ -17,3 +17,4 @@ Symlinks=%t/varlink/registry/io.systemd.JournalAccess
FileDescriptorName=varlink FileDescriptorName=varlink
SocketMode=0600 SocketMode=0600
Accept=yes Accept=yes
MaxConnectionsPerSource=16

View File

@ -12,4 +12,4 @@ Description=Journal Log Access Service
Documentation=man:journalctl(1) Documentation=man:journalctl(1)
[Service] [Service]
ExecStart=journalctl --user ExecStart=journalctl