mirror of
https://github.com/systemd/systemd.git
synced 2025-01-11 09:18:07 +03:00
Merge pull request #18481 from keszybz/rpm-restart-post-trans
Restart units after the rpm transaction
This commit is contained in:
commit
8f50eb04ac
@ -176,6 +176,7 @@ node /org/freedesktop/systemd1 {
|
||||
UnsetEnvironment(in as names);
|
||||
UnsetAndSetEnvironment(in as names,
|
||||
in as assignments);
|
||||
EnqueueMarkedJobs(out ao jobs);
|
||||
ListUnitFiles(out a(ss) unit_files);
|
||||
ListUnitFilesByPatterns(in as states,
|
||||
in as patterns,
|
||||
@ -848,6 +849,8 @@ node /org/freedesktop/systemd1 {
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="UnsetAndSetEnvironment()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="EnqueueMarkedJobs()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ListUnitFiles()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ListUnitFilesByPatterns()"/>
|
||||
@ -1171,6 +1174,11 @@ node /org/freedesktop/systemd1 {
|
||||
the "Try" flavor is used in which case a service that isn't running is not affected by the restart. The
|
||||
"ReloadOrRestart" flavors attempt a reload if the unit supports it and use a restart otherwise.</para>
|
||||
|
||||
<para><function>EnqueueMarkedJobs()</function> creates reload/restart jobs for units which have been
|
||||
appropriately marked, see <varname>Marks</varname> property above. This is equivalent to calling
|
||||
<function>TryRestartUnit()</function> or <function>ReloadOrTryRestartUnit()</function> for the marked
|
||||
units.</para>
|
||||
|
||||
<para><function>BindMountUnit()</function> can be used to bind mount new files or directories into
|
||||
a running service mount namespace.</para>
|
||||
|
||||
@ -1685,6 +1693,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
readonly b IgnoreOnIsolate = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b NeedDaemonReload = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||
readonly as Markers = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t JobTimeoutUSec = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
@ -1969,6 +1979,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NeedDaemonReload"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Markers"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="JobTimeoutUSec"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="JobRunningTimeoutUSec"/>
|
||||
@ -2160,8 +2172,16 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<para><varname>NeedDaemonReload</varname> is a boolean that indicates whether the configuration file
|
||||
this unit is loaded from (i.e. <varname>FragmentPath</varname> or <varname>SourcePath</varname>) has
|
||||
changed since the configuration was read and hence whether a configuration reload is
|
||||
recommended.</para>
|
||||
changed since the configuration was read and hence whether a configuration reload is recommended.
|
||||
</para>
|
||||
|
||||
<para><varname>Markers</varname> is an array of string flags that can be set using
|
||||
<function>SetUnitProperties()</function> to indicate that the service should be reloaded or
|
||||
restarted. Currently known values are <literal>needs-restart</literal> and
|
||||
<literal>needs-reload</literal>. Package scripts may use the first to mark units for later restart when
|
||||
a new version of the package is installed. Configuration management scripts may use the second to mark
|
||||
units for a later reload when the configuration is adjusted. Those flags are not set by the manager,
|
||||
except to unset as appropriate when when the unit is stopped, restarted, or reloaded.</para>
|
||||
|
||||
<para><varname>JobTimeoutUSec</varname> maps directly to the corresponding configuration setting in the
|
||||
unit file.</para>
|
||||
|
@ -36,11 +36,13 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><function>sd_bus_message_read_strv()</function> gives access to an array of strings in message
|
||||
<parameter>m</parameter>. The "read pointer" in the message must be right before an array of strings. On
|
||||
success, a pointer to the <constant>NULL</constant>-terminated array of strings is returned in the output
|
||||
parameter <parameter>l</parameter>. Note that ownership of this array is transferred to the caller.
|
||||
Hence, the caller is responsible for freeing this array and its contents.</para>
|
||||
<para><function>sd_bus_message_read_strv()</function> gives access to an array of string-like items in
|
||||
message <parameter>m</parameter>. The "read pointer" in the message must be right before an array of
|
||||
strings (D-Bus type <literal>as</literal>), object paths (D-Bus type <literal>ao</literal>), or
|
||||
signatures (D-Bus type <literal>ag</literal>). On success, a pointer to a
|
||||
<constant>NULL</constant>-terminated array of strings is returned in the output parameter
|
||||
<parameter>l</parameter>. Note that ownership of this array is transferred to the caller. Hence, the
|
||||
caller is responsible for freeing this array and its contents.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -73,6 +75,13 @@
|
||||
|
||||
<listitem><para>The message cannot be parsed.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-ENXIO</constant></term>
|
||||
|
||||
<listitem><para>The message "read pointer" is not right before an array of the appropriate type.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
@ -2304,6 +2304,18 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||
a directory, but a regular file, device node, socket or FIFO.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--marked</option></term>
|
||||
|
||||
<listitem><para>Only allowed with <command>reload-or-restart</command>. Enqueues restart jobs for all
|
||||
units that have the <literal>needs-restart</literal> mark, and reload jobs for units that have the
|
||||
<literal>needs-reload</literal> mark. When a unit marked for reload does not support reload, restart
|
||||
will be queued. Those properties can be set using <command>set-property Marks</command>.</para>
|
||||
|
||||
<para>Unless <option>--no-block</option> is used, <command>systemctl</command> will wait for the
|
||||
queued jobs to finish.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--read-only</option></term>
|
||||
|
||||
|
@ -1746,6 +1746,7 @@ subdir('src/partition')
|
||||
subdir('src/portable')
|
||||
subdir('src/pstore')
|
||||
subdir('src/resolve')
|
||||
subdir('src/rpm')
|
||||
subdir('src/shutdown')
|
||||
subdir('src/sysext')
|
||||
subdir('src/systemctl')
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "path-util.h"
|
||||
#include "strv.h"
|
||||
#include "unit-name.h"
|
||||
#include "unit-serialize.h"
|
||||
|
||||
static int prepare_filename(const char *filename, char **ret) {
|
||||
int r;
|
||||
|
@ -1277,7 +1277,7 @@ static int dot(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, "");
|
||||
r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, NULL);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
|
||||
|
||||
|
@ -117,6 +117,13 @@ static const char* const freezer_state_table[_FREEZER_STATE_MAX] = {
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(freezer_state, FreezerState);
|
||||
|
||||
static const char* const unit_marker_table[_UNIT_MARKER_MAX] = {
|
||||
[UNIT_MARKER_NEEDS_RELOAD] = "needs-reload",
|
||||
[UNIT_MARKER_NEEDS_RESTART] = "needs-restart",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(unit_marker, UnitMarker);
|
||||
|
||||
static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
|
||||
[AUTOMOUNT_DEAD] = "dead",
|
||||
[AUTOMOUNT_WAITING] = "waiting",
|
||||
|
@ -58,6 +58,13 @@ typedef enum FreezerState {
|
||||
_FREEZER_STATE_INVALID = -EINVAL,
|
||||
} FreezerState;
|
||||
|
||||
typedef enum UnitMarker {
|
||||
UNIT_MARKER_NEEDS_RELOAD,
|
||||
UNIT_MARKER_NEEDS_RESTART,
|
||||
_UNIT_MARKER_MAX,
|
||||
_UNIT_MARKER_INVALID = -1
|
||||
} UnitMarker;
|
||||
|
||||
typedef enum AutomountState {
|
||||
AUTOMOUNT_DEAD,
|
||||
AUTOMOUNT_WAITING,
|
||||
@ -267,6 +274,9 @@ UnitActiveState unit_active_state_from_string(const char *s) _pure_;
|
||||
const char *freezer_state_to_string(FreezerState i) _const_;
|
||||
FreezerState freezer_state_from_string(const char *s) _pure_;
|
||||
|
||||
const char *unit_marker_to_string(UnitMarker m) _const_;
|
||||
UnitMarker unit_marker_from_string(const char *s) _pure_;
|
||||
|
||||
const char* automount_state_to_string(AutomountState i) _const_;
|
||||
AutomountState automount_state_from_string(const char *s) _pure_;
|
||||
|
||||
|
@ -443,7 +443,7 @@ static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *p
|
||||
|
||||
r = sd_bus_call_method(bus, service, path,
|
||||
"org.freedesktop.DBus.Introspectable", "Introspect",
|
||||
&error, &reply, "");
|
||||
&error, &reply, NULL);
|
||||
if (r < 0) {
|
||||
printf("%sFailed to introspect object %s of service %s: %s%s\n",
|
||||
ansi_highlight_red(),
|
||||
@ -982,7 +982,7 @@ static int introspect(int argc, char **argv, void *userdata) {
|
||||
|
||||
r = sd_bus_call_method(bus, argv[1], argv[2],
|
||||
"org.freedesktop.DBus.Introspectable", "Introspect",
|
||||
&error, &reply_xml, "");
|
||||
&error, &reply_xml, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to introspect object %s of service %s: %s",
|
||||
argv[2], argv[1], bus_error_message(&error, r));
|
||||
|
@ -38,8 +38,8 @@
|
||||
#include "virt.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
/* Require 16MiB free in /run/systemd for reloading/reexecing. After all we need to serialize our state there, and if
|
||||
* we can't we'll fail badly. */
|
||||
/* Require 16MiB free in /run/systemd for reloading/reexecing. After all we need to serialize our state
|
||||
* there, and if we can't we'll fail badly. */
|
||||
#define RELOAD_DISK_SPACE_MIN (UINT64_C(16) * UINT64_C(1024) * UINT64_C(1024))
|
||||
|
||||
static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) {
|
||||
@ -363,8 +363,8 @@ static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char
|
||||
assert(message);
|
||||
assert(ret_unit);
|
||||
|
||||
/* More or less a wrapper around manager_get_unit() that generates nice errors and has one trick up its sleeve:
|
||||
* if the name is specified empty we use the client's unit. */
|
||||
/* More or less a wrapper around manager_get_unit() that generates nice errors and has one trick up
|
||||
* its sleeve: if the name is specified empty we use the client's unit. */
|
||||
|
||||
if (isempty(name)) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
@ -520,7 +520,8 @@ static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userd
|
||||
|
||||
u = manager_get_unit_by_pid(m, pid);
|
||||
if (!u)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client " PID_FMT " not member of any unit.", pid);
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT,
|
||||
"Client " PID_FMT " not member of any unit.", pid);
|
||||
} else {
|
||||
u = hashmap_get(m->units_by_invocation_id, &id);
|
||||
if (!u)
|
||||
@ -531,8 +532,9 @@ static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userd
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* So here's a special trick: the bus path we return actually references the unit by its invocation ID instead
|
||||
* of the unit name. This means it stays valid only as long as the invocation ID stays the same. */
|
||||
/* So here's a special trick: the bus path we return actually references the unit by its invocation
|
||||
* ID instead of the unit name. This means it stays valid only as long as the invocation ID stays the
|
||||
* same. */
|
||||
path = unit_dbus_path_invocation_id(u);
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
@ -552,7 +554,9 @@ static int method_get_unit_by_control_group(sd_bus_message *message, void *userd
|
||||
|
||||
u = manager_get_unit_by_cgroup(m, cgroup);
|
||||
if (!u)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Control group '%s' is not valid or not managed by this instance", cgroup);
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT,
|
||||
"Control group '%s' is not valid or not managed by this instance",
|
||||
cgroup);
|
||||
|
||||
return reply_unit_path(u, message, error);
|
||||
}
|
||||
@ -851,17 +855,21 @@ static int transient_unit_from_message(
|
||||
|
||||
t = unit_name_to_type(name);
|
||||
if (t < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name or type.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Invalid unit name or type.");
|
||||
|
||||
if (!unit_vtable[t]->can_transient)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Unit type %s does not support transient units.",
|
||||
unit_type_to_string(t));
|
||||
|
||||
r = manager_load_unit(m, name, NULL, error, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!unit_is_pristine(u))
|
||||
return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
|
||||
return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
|
||||
"Unit %s already exists.", name);
|
||||
|
||||
/* OK, the unit failed to load and is unreferenced, now let's
|
||||
* fill in the transient data instead */
|
||||
@ -1435,7 +1443,8 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
|
||||
return r;
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(m))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||
"Reboot is only supported for system managers.");
|
||||
|
||||
m->objective = MANAGER_REBOOT;
|
||||
|
||||
@ -1454,7 +1463,8 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error
|
||||
return r;
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(m))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||
"Powering off is only supported for system managers.");
|
||||
|
||||
m->objective = MANAGER_POWEROFF;
|
||||
|
||||
@ -1473,7 +1483,8 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er
|
||||
return r;
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(m))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||
"Halt is only supported for system managers.");
|
||||
|
||||
m->objective = MANAGER_HALT;
|
||||
|
||||
@ -1492,7 +1503,8 @@ static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *e
|
||||
return r;
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(m))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||
"KExec is only supported for system managers.");
|
||||
|
||||
m->objective = MANAGER_KEXEC;
|
||||
|
||||
@ -1517,7 +1529,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
|
||||
|
||||
if (available < RELOAD_DISK_SPACE_MIN) {
|
||||
char fb_available[FORMAT_BYTES_MAX], fb_need[FORMAT_BYTES_MAX];
|
||||
log_warning("Dangerously low amount of free space on /run/systemd, root switching operation might not complete successfully. "
|
||||
log_warning("Dangerously low amount of free space on /run/systemd, root switching might fail.\n"
|
||||
"Currently, %s are free, but %s are suggested. Proceeding anyway.",
|
||||
format_bytes(fb_available, sizeof(fb_available), available),
|
||||
format_bytes(fb_need, sizeof(fb_need), RELOAD_DISK_SPACE_MIN));
|
||||
@ -1528,41 +1540,53 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
|
||||
return r;
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(m))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Root switching is only supported by system manager.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||
"Root switching is only supported by system manager.");
|
||||
|
||||
r = sd_bus_message_read(message, "ss", &root, &init);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (isempty(root))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root directory may not be the empty string.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"New root directory may not be the empty string.");
|
||||
if (!path_is_absolute(root))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root path '%s' is not absolute.", root);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"New root path '%s' is not absolute.", root);
|
||||
if (path_equal(root, "/"))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root directory cannot be the old root directory.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"New root directory cannot be the old root directory.");
|
||||
|
||||
/* Safety check */
|
||||
if (isempty(init)) {
|
||||
r = path_is_os_tree(root);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to determine whether root path '%s' contains an OS tree: %m", root);
|
||||
return sd_bus_error_set_errnof(error, r,
|
||||
"Failed to determine whether root path '%s' contains an OS tree: %m",
|
||||
root);
|
||||
if (r == 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.", root);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.",
|
||||
root);
|
||||
} else {
|
||||
_cleanup_free_ char *chased = NULL;
|
||||
|
||||
if (!path_is_absolute(init))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path to init binary '%s' not absolute.", init);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Path to init binary '%s' not absolute.", init);
|
||||
|
||||
r = chase_symlinks(init, root, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &chased, NULL);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Could not resolve init executable %s: %m", init);
|
||||
return sd_bus_error_set_errnof(error, r,
|
||||
"Could not resolve init executable %s: %m", init);
|
||||
|
||||
if (laccess(chased, X_OK) < 0) {
|
||||
if (errno == EACCES)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Init binary %s is not executable.", init);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Init binary %s is not executable.", init);
|
||||
|
||||
return sd_bus_error_set_errnof(error, r, "Could not check whether init binary %s is executable: %m", init);
|
||||
return sd_bus_error_set_errnof(error, r,
|
||||
"Could not check whether init binary %s is executable: %m", init);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1632,7 +1656,8 @@ static int method_unset_environment(sd_bus_message *message, void *userdata, sd_
|
||||
return r;
|
||||
|
||||
if (!strv_env_name_or_assignment_is_valid(minus))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Invalid environment variable names or assignments");
|
||||
|
||||
r = bus_verify_set_environment_async(m, message, error);
|
||||
if (r < 0)
|
||||
@ -1668,9 +1693,11 @@ static int method_unset_and_set_environment(sd_bus_message *message, void *userd
|
||||
return r;
|
||||
|
||||
if (!strv_env_name_or_assignment_is_valid(minus))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Invalid environment variable names or assignments");
|
||||
if (!strv_env_is_valid(plus))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Invalid environment assignments");
|
||||
|
||||
r = bus_verify_set_environment_async(m, message, error);
|
||||
if (r < 0)
|
||||
@ -1723,13 +1750,16 @@ static int method_lookup_dynamic_user_by_name(sd_bus_message *message, void *use
|
||||
return r;
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(m))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||
"Dynamic users are only supported in the system instance.");
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name invalid: %s", name);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"User name invalid: %s", name);
|
||||
|
||||
r = dynamic_user_lookup_name(m, name, &uid);
|
||||
if (r == -ESRCH)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER, "Dynamic user %s does not exist.", name);
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER,
|
||||
"Dynamic user %s does not exist.", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1751,13 +1781,16 @@ static int method_lookup_dynamic_user_by_uid(sd_bus_message *message, void *user
|
||||
return r;
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(m))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||
"Dynamic users are only supported in the system instance.");
|
||||
if (!uid_is_valid(uid))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User ID invalid: " UID_FMT, uid);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"User ID invalid: " UID_FMT, uid);
|
||||
|
||||
r = dynamic_user_lookup_uid(m, uid, &name);
|
||||
if (r == -ESRCH)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER, "Dynamic user ID " UID_FMT " does not exist.", uid);
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER,
|
||||
"Dynamic user ID " UID_FMT " does not exist.", uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1776,7 +1809,8 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_
|
||||
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(m))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
|
||||
"Dynamic users are only supported in the system instance.");
|
||||
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
if (r < 0)
|
||||
@ -1793,7 +1827,8 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_
|
||||
if (r == -EAGAIN) /* not realized yet? */
|
||||
continue;
|
||||
if (r < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to look up a dynamic user.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED,
|
||||
"Failed to look up a dynamic user.");
|
||||
|
||||
r = sd_bus_message_append(reply, "(us)", uid, d->name);
|
||||
if (r < 0)
|
||||
@ -1807,6 +1842,75 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static int method_enqueue_marked_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = userdata;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
r = mac_selinux_access_check(message, "start", error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_verify_manage_units_async(m, message, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||
|
||||
log_info("Queuing reload/restart jobs for marked units…");
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "o");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
Unit *u;
|
||||
char *k;
|
||||
int ret = 0;
|
||||
HASHMAP_FOREACH_KEY(u, k, m->units) {
|
||||
/* ignore aliases */
|
||||
if (u->id != k)
|
||||
continue;
|
||||
|
||||
BusUnitQueueFlags flags;
|
||||
if (FLAGS_SET(u->markers, 1u << UNIT_MARKER_NEEDS_RESTART))
|
||||
flags = 0;
|
||||
else if (FLAGS_SET(u->markers, 1u << UNIT_MARKER_NEEDS_RELOAD))
|
||||
flags = BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
|
||||
else
|
||||
continue;
|
||||
|
||||
r = mac_selinux_unit_access_check(u, message, "start", error);
|
||||
if (r >= 0)
|
||||
r = bus_unit_queue_job_one(message, u,
|
||||
JOB_TRY_RESTART, JOB_FAIL, flags,
|
||||
reply, error);
|
||||
if (r < 0) {
|
||||
if (ERRNO_IS_RESOURCE(r))
|
||||
return r;
|
||||
if (ret >= 0)
|
||||
ret = r;
|
||||
sd_bus_error_free(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return sd_bus_error_set_errnof(error, ret,
|
||||
"Failed to enqueue some jobs, see logs for details: %m");
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
Manager *m = userdata;
|
||||
@ -1932,7 +2036,10 @@ static int send_unit_files_changed(sd_bus *bus, void *userdata) {
|
||||
|
||||
assert(bus);
|
||||
|
||||
r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
|
||||
r = sd_bus_message_new_signal(bus, &message,
|
||||
"/org/freedesktop/systemd1",
|
||||
"org.freedesktop.systemd1.Manager",
|
||||
"UnitFilesChanged");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -2060,8 +2167,8 @@ static int reply_unit_file_changes_and_free(
|
||||
good = true;
|
||||
}
|
||||
|
||||
/* If there was a failed change, and no successful change, then return the first failure as proper method call
|
||||
* error. */
|
||||
/* If there was a failed change, and no successful change, then return the first failure as proper
|
||||
* method call error. */
|
||||
if (bad && !good)
|
||||
return install_error(error, 0, changes, n_changes);
|
||||
|
||||
@ -2486,7 +2593,8 @@ static int method_abandon_scope(sd_bus_message *message, void *userdata, sd_bus_
|
||||
return r;
|
||||
|
||||
if (u->type != UNIT_SCOPE)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit '%s' is not a scope unit, refusing.", name);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Unit '%s' is not a scope unit, refusing.", name);
|
||||
|
||||
return bus_scope_method_abandon(message, u, error);
|
||||
}
|
||||
@ -2507,7 +2615,8 @@ static int method_set_show_status(sd_bus_message *message, void *userdata, sd_bu
|
||||
if (!isempty(t)) {
|
||||
mode = show_status_from_string(t);
|
||||
if (mode < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid show status '%s'", t);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Invalid show status '%s'", t);
|
||||
}
|
||||
|
||||
manager_override_show_status(m, mode, "bus");
|
||||
@ -3007,6 +3116,12 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
||||
NULL,,
|
||||
method_unset_and_set_environment,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("EnqueueMarkedJobs",
|
||||
NULL,,
|
||||
"ao",
|
||||
SD_BUS_PARAM(jobs),
|
||||
method_enqueue_marked_jobs,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ListUnitFiles",
|
||||
NULL,,
|
||||
"a(ss)",
|
||||
@ -3260,7 +3375,11 @@ static int send_finished(sd_bus *bus, void *userdata) {
|
||||
assert(bus);
|
||||
assert(times);
|
||||
|
||||
r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
|
||||
r = sd_bus_message_new_signal(bus,
|
||||
&message,
|
||||
"/org/freedesktop/systemd1",
|
||||
"org.freedesktop.systemd1.Manager",
|
||||
"StartupFinished");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -323,6 +323,39 @@ static int property_get_load_error(
|
||||
return sd_bus_message_append(reply, "(ss)", NULL, NULL);
|
||||
}
|
||||
|
||||
static int property_get_markers(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
unsigned *markers = userdata;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
assert(markers);
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "s");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Make sure out values fit in the bitfield. */
|
||||
assert_cc(_UNIT_MARKER_MAX <= sizeof(((Unit){}).markers) * 8);
|
||||
|
||||
for (UnitMarker m = 0; m < _UNIT_MARKER_MAX; m++)
|
||||
if (FLAGS_SET(*markers, 1u << m)) {
|
||||
r = sd_bus_message_append(reply, "s", unit_marker_to_string(m));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
|
||||
[JOB_START] = N_("Authentication is required to start '$(unit)'."),
|
||||
[JOB_STOP] = N_("Authentication is required to stop '$(unit)'."),
|
||||
@ -778,7 +811,6 @@ static int property_get_refs(
|
||||
sd_bus_error *error) {
|
||||
|
||||
Unit *u = userdata;
|
||||
const char *i;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
@ -788,15 +820,15 @@ static int property_get_refs(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (i = sd_bus_track_first(u->bus_track); i; i = sd_bus_track_next(u->bus_track)) {
|
||||
int c, k;
|
||||
for (const char *i = sd_bus_track_first(u->bus_track); i; i = sd_bus_track_next(u->bus_track)) {
|
||||
int c;
|
||||
|
||||
c = sd_bus_track_count_name(u->bus_track, i);
|
||||
if (c < 0)
|
||||
return c;
|
||||
|
||||
/* Add the item multiple times if the ref count for each is above 1 */
|
||||
for (k = 0; k < c; k++) {
|
||||
for (int k = 0; k < c; k++) {
|
||||
r = sd_bus_message_append(reply, "s", i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -864,6 +896,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
|
||||
SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Markers", "as", property_get_markers, offsetof(Unit, markers), 0),
|
||||
SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_running_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_emergency_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@ -1683,6 +1716,89 @@ void bus_unit_send_removed_signal(Unit *u) {
|
||||
log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id);
|
||||
}
|
||||
|
||||
int bus_unit_queue_job_one(
|
||||
sd_bus_message *message,
|
||||
Unit *u,
|
||||
JobType type,
|
||||
JobMode mode,
|
||||
BusUnitQueueFlags flags,
|
||||
sd_bus_message *reply,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_set_free_ Set *affected = NULL;
|
||||
_cleanup_free_ char *job_path = NULL, *unit_path = NULL;
|
||||
Job *j, *a;
|
||||
int r;
|
||||
|
||||
if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
|
||||
affected = set_new(NULL);
|
||||
if (!affected)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = manager_add_job(u->manager, type, u, mode, affected, error, &j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_job_track_sender(j, message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Before we send the method reply, force out the announcement JobNew for this job */
|
||||
bus_job_send_pending_change_signal(j, true);
|
||||
|
||||
job_path = job_dbus_path(j);
|
||||
if (!job_path)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The classic response is just a job object path */
|
||||
if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY))
|
||||
return sd_bus_message_append(reply, "o", job_path);
|
||||
|
||||
/* In verbose mode respond with the anchor job plus everything that has been affected */
|
||||
|
||||
unit_path = unit_dbus_path(j->unit);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "uosos",
|
||||
j->id, job_path,
|
||||
j->unit->id, unit_path,
|
||||
job_type_to_string(j->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(uosos)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FOREACH(a, affected) {
|
||||
if (a->id == j->id)
|
||||
continue;
|
||||
|
||||
/* Free paths from previous iteration */
|
||||
job_path = mfree(job_path);
|
||||
unit_path = mfree(unit_path);
|
||||
|
||||
job_path = job_dbus_path(a);
|
||||
if (!job_path)
|
||||
return -ENOMEM;
|
||||
|
||||
unit_path = unit_dbus_path(a->unit);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "(uosos)",
|
||||
a->id, job_path,
|
||||
a->unit->id, unit_path,
|
||||
job_type_to_string(a->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
int bus_unit_queue_job(
|
||||
sd_bus_message *message,
|
||||
Unit *u,
|
||||
@ -1692,9 +1808,6 @@ int bus_unit_queue_job(
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_free_ char *job_path = NULL, *unit_path = NULL;
|
||||
_cleanup_set_free_ Set *affected = NULL;
|
||||
Job *j, *a;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
@ -1727,77 +1840,11 @@ int bus_unit_queue_job(
|
||||
(type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
|
||||
return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
|
||||
|
||||
if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
|
||||
affected = set_new(NULL);
|
||||
if (!affected)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = manager_add_job(u->manager, type, u, mode, affected, error, &j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_job_track_sender(j, message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Before we send the method reply, force out the announcement JobNew for this job */
|
||||
bus_job_send_pending_change_signal(j, true);
|
||||
|
||||
job_path = job_dbus_path(j);
|
||||
if (!job_path)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The classic response is just a job object path */
|
||||
if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY))
|
||||
return sd_bus_reply_method_return(message, "o", job_path);
|
||||
|
||||
/* In verbose mode respond with the anchor job plus everything that has been affected */
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
unit_path = unit_dbus_path(j->unit);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "uosos",
|
||||
j->id, job_path,
|
||||
j->unit->id, unit_path,
|
||||
job_type_to_string(j->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(uosos)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FOREACH(a, affected) {
|
||||
|
||||
if (a->id == j->id)
|
||||
continue;
|
||||
|
||||
/* Free paths from previous iteration */
|
||||
job_path = mfree(job_path);
|
||||
unit_path = mfree(unit_path);
|
||||
|
||||
job_path = job_dbus_path(a);
|
||||
if (!job_path)
|
||||
return -ENOMEM;
|
||||
|
||||
unit_path = unit_dbus_path(a->unit);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "(uosos)",
|
||||
a->id, job_path,
|
||||
a->unit->id, unit_path,
|
||||
job_type_to_string(a->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
r = bus_unit_queue_job_one(message, u, type, mode, flags, reply, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1817,8 +1864,8 @@ static int bus_unit_set_live_property(
|
||||
assert(name);
|
||||
assert(message);
|
||||
|
||||
/* Handles setting properties both "live" (i.e. at any time during runtime), and during creation (for transient
|
||||
* units that are being created). */
|
||||
/* Handles setting properties both "live" (i.e. at any time during runtime), and during creation (for
|
||||
* transient units that are being created). */
|
||||
|
||||
if (streq(name, "Description")) {
|
||||
const char *d;
|
||||
@ -1838,6 +1885,63 @@ static int bus_unit_set_live_property(
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* A setting that only applies to active units. We don't actually write this to /run, this state is
|
||||
* managed internally. "+foo" sets flag foo, "-foo" unsets flag foo, just "foo" resets flags to
|
||||
* foo. The last type cannot be mixed with "+" or "-". */
|
||||
|
||||
if (streq(name, "Markers")) {
|
||||
unsigned settings = 0, mask = 0;
|
||||
bool some_plus_minus = false, some_absolute = false;
|
||||
|
||||
r = sd_bus_message_enter_container(message, 'a', "s");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
const char *word;
|
||||
bool b;
|
||||
|
||||
r = sd_bus_message_read(message, "s", &word);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (IN_SET(word[0], '+', '-')) {
|
||||
b = word[0] == '+';
|
||||
word++;
|
||||
some_plus_minus = true;
|
||||
} else {
|
||||
b = true;
|
||||
some_absolute = true;
|
||||
}
|
||||
|
||||
UnitMarker m = unit_marker_from_string(word);
|
||||
if (m < 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING,
|
||||
"Unknown marker \"%s\".", word);
|
||||
|
||||
SET_FLAG(settings, 1u << m, b);
|
||||
SET_FLAG(mask, 1u << m, true);
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (some_plus_minus && some_absolute)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING, "Bad marker syntax.");
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
if (some_absolute)
|
||||
u->markers = settings;
|
||||
else
|
||||
u->markers = settings | (u->markers & ~mask);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1989,8 +2093,8 @@ static int bus_unit_set_transient_property(
|
||||
assert(name);
|
||||
assert(message);
|
||||
|
||||
/* Handles settings when transient units are created. This settings cannot be altered anymore after the unit
|
||||
* has been created. */
|
||||
/* Handles settings when transient units are created. This settings cannot be altered anymore after
|
||||
* the unit has been created. */
|
||||
|
||||
if (streq(name, "SourcePath"))
|
||||
return bus_set_transient_path(u, name, &u->source_path, message, flags, error);
|
||||
@ -2298,7 +2402,8 @@ int bus_unit_set_properties(
|
||||
return r;
|
||||
|
||||
if (!UNIT_VTABLE(u)->bus_set_property)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY,
|
||||
"Objects of this type do not support setting properties.");
|
||||
|
||||
r = sd_bus_message_enter_container(message, 'v', NULL);
|
||||
if (r < 0)
|
||||
@ -2316,7 +2421,8 @@ int bus_unit_set_properties(
|
||||
return r;
|
||||
|
||||
if (r == 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY,
|
||||
"Cannot set property %s, or unknown property.", name);
|
||||
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
@ -2435,8 +2541,8 @@ int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) {
|
||||
int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m) {
|
||||
assert(u);
|
||||
|
||||
/* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an
|
||||
* error */
|
||||
/* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet,
|
||||
* return an error */
|
||||
if (!u->bus_track)
|
||||
return -EUNATCH;
|
||||
|
||||
|
@ -33,7 +33,21 @@ typedef enum BusUnitQueueFlags {
|
||||
BUS_UNIT_QUEUE_VERBOSE_REPLY = 1 << 1,
|
||||
} BusUnitQueueFlags;
|
||||
|
||||
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, BusUnitQueueFlags flags, sd_bus_error *error);
|
||||
int bus_unit_queue_job_one(
|
||||
sd_bus_message *message,
|
||||
Unit *u,
|
||||
JobType type,
|
||||
JobMode mode,
|
||||
BusUnitQueueFlags flags,
|
||||
sd_bus_message *reply,
|
||||
sd_bus_error *error);
|
||||
int bus_unit_queue_job(
|
||||
sd_bus_message *message,
|
||||
Unit *u,
|
||||
JobType type,
|
||||
JobMode mode,
|
||||
BusUnitQueueFlags flags,
|
||||
sd_bus_error *error);
|
||||
int bus_unit_validate_load_state(Unit *u, sd_bus_error *error);
|
||||
|
||||
int bus_unit_track_add_name(Unit *u, const char *name);
|
||||
|
@ -93,7 +93,7 @@
|
||||
#include "terminal-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "umask-util.h"
|
||||
#include "unit.h"
|
||||
#include "unit-serialize.h"
|
||||
#include "user-util.h"
|
||||
#include "utmp-wtmp.h"
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "install.h"
|
||||
#include "load-fragment.h"
|
||||
#include "string-util.h"
|
||||
#include "unit.h"
|
||||
#include "unit-serialize.h"
|
||||
#include "utf8.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
|
@ -80,6 +80,7 @@
|
||||
#include "transaction.h"
|
||||
#include "umask-util.h"
|
||||
#include "unit-name.h"
|
||||
#include "unit-serialize.h"
|
||||
#include "user-util.h"
|
||||
#include "virt.h"
|
||||
#include "watchdog.h"
|
||||
@ -1187,18 +1188,15 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
|
||||
is_bad = false;
|
||||
}
|
||||
|
||||
if (u->refs_by_target) {
|
||||
const UnitRef *ref;
|
||||
const UnitRef *ref;
|
||||
LIST_FOREACH(refs_by_target, ref, u->refs_by_target) {
|
||||
unit_gc_sweep(ref->source, gc_marker);
|
||||
|
||||
LIST_FOREACH(refs_by_target, ref, u->refs_by_target) {
|
||||
unit_gc_sweep(ref->source, gc_marker);
|
||||
if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD)
|
||||
goto good;
|
||||
|
||||
if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD)
|
||||
goto good;
|
||||
|
||||
if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD)
|
||||
is_bad = false;
|
||||
}
|
||||
if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD)
|
||||
is_bad = false;
|
||||
}
|
||||
|
||||
if (is_bad)
|
||||
|
@ -115,6 +115,8 @@ libcore_sources = '''
|
||||
transaction.h
|
||||
unit-printf.c
|
||||
unit-printf.h
|
||||
unit-serialize.c
|
||||
unit-serialize.h
|
||||
unit.c
|
||||
unit.h
|
||||
'''.split()
|
||||
@ -162,11 +164,9 @@ core_includes = [includes, include_directories('.')]
|
||||
|
||||
systemd_sources = files('main.c')
|
||||
|
||||
in_files = [['macros.systemd', rpmmacrosdir],
|
||||
['system.conf', pkgsysconfdir],
|
||||
in_files = [['system.conf', pkgsysconfdir],
|
||||
['user.conf', pkgsysconfdir],
|
||||
['systemd.pc', pkgconfigdatadir],
|
||||
['triggers.systemd', '']]
|
||||
['systemd.pc', pkgconfigdatadir]]
|
||||
|
||||
foreach item : in_files
|
||||
file = item[0]
|
||||
|
780
src/core/unit-serialize.c
Normal file
780
src/core/unit-serialize.c
Normal file
@ -0,0 +1,780 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "bus-util.h"
|
||||
#include "dbus.h"
|
||||
#include "fileio-label.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "serialize.h"
|
||||
#include "string-table.h"
|
||||
#include "unit-serialize.h"
|
||||
#include "user-util.h"
|
||||
|
||||
static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
assert(key);
|
||||
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
|
||||
r = cg_mask_to_string(mask, &s);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format cgroup mask: %m");
|
||||
|
||||
return serialize_item(f, key, s);
|
||||
}
|
||||
|
||||
/* Make sure out values fit in the bitfield. */
|
||||
assert_cc(_UNIT_MARKER_MAX <= sizeof(((Unit){}).markers) * 8);
|
||||
|
||||
static int serialize_markers(FILE *f, unsigned markers) {
|
||||
assert(f);
|
||||
|
||||
if (markers == 0)
|
||||
return 0;
|
||||
|
||||
fputs("markers=", f);
|
||||
for (UnitMarker m = 0; m < _UNIT_MARKER_MAX; m++)
|
||||
if (FLAGS_SET(markers, 1u << m))
|
||||
fputs(unit_marker_to_string(m), f);
|
||||
fputc('\n', f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int deserialize_markers(Unit *u, const char *value) {
|
||||
assert(u);
|
||||
assert(value);
|
||||
int r;
|
||||
|
||||
for (const char *p = value;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, 0);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
UnitMarker m = unit_marker_from_string(word);
|
||||
if (m < 0) {
|
||||
log_unit_debug_errno(u, m, "Unknown unit marker \"%s\", ignoring.", word);
|
||||
continue;
|
||||
}
|
||||
|
||||
u->markers |= 1u << m;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes",
|
||||
[CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets",
|
||||
[CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes",
|
||||
[CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets",
|
||||
};
|
||||
|
||||
static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base",
|
||||
[CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base",
|
||||
};
|
||||
|
||||
static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last",
|
||||
[CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last",
|
||||
};
|
||||
|
||||
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
assert(fds);
|
||||
|
||||
if (unit_can_serialize(u)) {
|
||||
r = UNIT_VTABLE(u)->serialize(u, f, fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
(void) serialize_dual_timestamp(f, "state-change-timestamp", &u->state_change_timestamp);
|
||||
|
||||
(void) serialize_dual_timestamp(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "active-enter-timestamp", &u->active_enter_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "active-exit-timestamp", &u->active_exit_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
|
||||
|
||||
(void) serialize_dual_timestamp(f, "condition-timestamp", &u->condition_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "assert-timestamp", &u->assert_timestamp);
|
||||
|
||||
if (dual_timestamp_is_set(&u->condition_timestamp))
|
||||
(void) serialize_bool(f, "condition-result", u->condition_result);
|
||||
|
||||
if (dual_timestamp_is_set(&u->assert_timestamp))
|
||||
(void) serialize_bool(f, "assert-result", u->assert_result);
|
||||
|
||||
(void) serialize_bool(f, "transient", u->transient);
|
||||
(void) serialize_bool(f, "in-audit", u->in_audit);
|
||||
|
||||
(void) serialize_bool(f, "exported-invocation-id", u->exported_invocation_id);
|
||||
(void) serialize_bool(f, "exported-log-level-max", u->exported_log_level_max);
|
||||
(void) serialize_bool(f, "exported-log-extra-fields", u->exported_log_extra_fields);
|
||||
(void) serialize_bool(f, "exported-log-rate-limit-interval", u->exported_log_ratelimit_interval);
|
||||
(void) serialize_bool(f, "exported-log-rate-limit-burst", u->exported_log_ratelimit_burst);
|
||||
|
||||
(void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base);
|
||||
if (u->cpu_usage_last != NSEC_INFINITY)
|
||||
(void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last);
|
||||
|
||||
if (u->managed_oom_kill_last > 0)
|
||||
(void) serialize_item_format(f, "managed-oom-kill-last", "%" PRIu64, u->managed_oom_kill_last);
|
||||
|
||||
if (u->oom_kill_last > 0)
|
||||
(void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last);
|
||||
|
||||
for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) {
|
||||
(void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]);
|
||||
|
||||
if (u->io_accounting_last[im] != UINT64_MAX)
|
||||
(void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]);
|
||||
}
|
||||
|
||||
if (u->cgroup_path)
|
||||
(void) serialize_item(f, "cgroup", u->cgroup_path);
|
||||
|
||||
(void) serialize_bool(f, "cgroup-realized", u->cgroup_realized);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask);
|
||||
|
||||
if (uid_is_valid(u->ref_uid))
|
||||
(void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid);
|
||||
if (gid_is_valid(u->ref_gid))
|
||||
(void) serialize_item_format(f, "ref-gid", GID_FMT, u->ref_gid);
|
||||
|
||||
if (!sd_id128_is_null(u->invocation_id))
|
||||
(void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id));
|
||||
|
||||
(void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u)));
|
||||
(void) serialize_markers(f, u->markers);
|
||||
|
||||
bus_track_serialize(u->bus_track, f, "ref");
|
||||
|
||||
for (CGroupIPAccountingMetric m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
|
||||
uint64_t v;
|
||||
|
||||
r = unit_get_ip_accounting(u, m, &v);
|
||||
if (r >= 0)
|
||||
(void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v);
|
||||
}
|
||||
|
||||
if (serialize_jobs) {
|
||||
if (u->job) {
|
||||
fputs("job\n", f);
|
||||
job_serialize(u->job, f);
|
||||
}
|
||||
|
||||
if (u->nop_job) {
|
||||
fputs("job\n", f);
|
||||
job_serialize(u->nop_job, f);
|
||||
}
|
||||
}
|
||||
|
||||
/* End marker */
|
||||
fputc('\n', f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unit_deserialize_job(Unit *u, FILE *f) {
|
||||
_cleanup_(job_freep) Job *j = NULL;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
|
||||
j = job_new_raw(u);
|
||||
if (!j)
|
||||
return log_oom();
|
||||
|
||||
r = job_deserialize(j, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = job_install_deserialized(j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(j);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MATCH_DESERIALIZE(key, l, v, parse_func, target) \
|
||||
({ \
|
||||
bool _deserialize_matched = streq(l, key); \
|
||||
if (_deserialize_matched) { \
|
||||
int _deserialize_r = parse_func(v); \
|
||||
if (_deserialize_r < 0) \
|
||||
log_unit_debug_errno(u, _deserialize_r, \
|
||||
"Failed to parse \"%s=%s\", ignoring.", l, v); \
|
||||
else \
|
||||
target = _deserialize_r; \
|
||||
}; \
|
||||
_deserialize_matched; \
|
||||
})
|
||||
|
||||
#define MATCH_DESERIALIZE_IMMEDIATE(key, l, v, parse_func, target) \
|
||||
({ \
|
||||
bool _deserialize_matched = streq(l, key); \
|
||||
if (_deserialize_matched) { \
|
||||
int _deserialize_r = parse_func(v, &target); \
|
||||
if (_deserialize_r < 0) \
|
||||
log_unit_debug_errno(u, _deserialize_r, \
|
||||
"Failed to parse \"%s=%s\", ignoring", l, v); \
|
||||
}; \
|
||||
_deserialize_matched; \
|
||||
})
|
||||
|
||||
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
assert(fds);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
char *l, *v;
|
||||
ssize_t m;
|
||||
size_t k;
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read serialization line: %m");
|
||||
if (r == 0) /* eof */
|
||||
break;
|
||||
|
||||
l = strstrip(line);
|
||||
if (isempty(l)) /* End marker */
|
||||
break;
|
||||
|
||||
k = strcspn(l, "=");
|
||||
|
||||
if (l[k] == '=') {
|
||||
l[k] = 0;
|
||||
v = l+k+1;
|
||||
} else
|
||||
v = l+k;
|
||||
|
||||
if (streq(l, "job")) {
|
||||
if (v[0] == '\0') {
|
||||
/* New-style serialized job */
|
||||
r = unit_deserialize_job(u, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else /* Legacy for pre-44 */
|
||||
log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
|
||||
continue;
|
||||
} else if (streq(l, "state-change-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->state_change_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "inactive-exit-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->inactive_exit_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "active-enter-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->active_enter_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "active-exit-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->active_exit_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "inactive-enter-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->inactive_enter_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "condition-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->condition_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "assert-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->assert_timestamp);
|
||||
continue;
|
||||
|
||||
} else if (MATCH_DESERIALIZE("condition-result", l, v, parse_boolean, u->condition_result))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE("assert-result", l, v, parse_boolean, u->assert_result))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE("transient", l, v, parse_boolean, u->transient))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE("in-audit", l, v, parse_boolean, u->in_audit))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE("exported-invocation-id", l, v, parse_boolean, u->exported_invocation_id))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE("exported-log-level-max", l, v, parse_boolean, u->exported_log_level_max))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE("exported-log-extra-fields", l, v, parse_boolean, u->exported_log_extra_fields))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE("exported-log-rate-limit-interval", l, v, parse_boolean, u->exported_log_ratelimit_interval))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE("exported-log-rate-limit-burst", l, v, parse_boolean, u->exported_log_ratelimit_burst))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE_IMMEDIATE("cpu-usage-base", l, v, safe_atou64, u->cpu_usage_base) ||
|
||||
MATCH_DESERIALIZE_IMMEDIATE("cpuacct-usage-base", l, v, safe_atou64, u->cpu_usage_base))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE_IMMEDIATE("cpu-usage-last", l, v, safe_atou64, u->cpu_usage_last))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE_IMMEDIATE("managed-oom-kill-last", l, v, safe_atou64, u->managed_oom_kill_last))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE_IMMEDIATE("oom-kill-last", l, v, safe_atou64, u->oom_kill_last))
|
||||
continue;
|
||||
|
||||
else if (streq(l, "cgroup")) {
|
||||
r = unit_set_cgroup_path(u, v);
|
||||
if (r < 0)
|
||||
log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v);
|
||||
|
||||
(void) unit_watch_cgroup(u);
|
||||
(void) unit_watch_cgroup_memory(u);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (MATCH_DESERIALIZE("cgroup-realized", l, v, parse_boolean, u->cgroup_realized))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-realized-mask", l, v, cg_mask_from_string, u->cgroup_realized_mask))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-enabled-mask", l, v, cg_mask_from_string, u->cgroup_enabled_mask))
|
||||
continue;
|
||||
|
||||
else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-invalidated-mask", l, v, cg_mask_from_string, u->cgroup_invalidated_mask))
|
||||
continue;
|
||||
|
||||
else if (streq(l, "ref-uid")) {
|
||||
uid_t uid;
|
||||
|
||||
r = parse_uid(v, &uid);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v);
|
||||
else
|
||||
unit_ref_uid_gid(u, uid, GID_INVALID);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref-gid")) {
|
||||
gid_t gid;
|
||||
|
||||
r = parse_gid(v, &gid);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v);
|
||||
else
|
||||
unit_ref_uid_gid(u, UID_INVALID, gid);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref")) {
|
||||
r = strv_extend(&u->deserialized_refs, v);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "invocation-id")) {
|
||||
sd_id128_t id;
|
||||
|
||||
r = sd_id128_from_string(v, &id);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v);
|
||||
else {
|
||||
r = unit_set_invocation_id(u, id);
|
||||
if (r < 0)
|
||||
log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m");
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
} else if (MATCH_DESERIALIZE("freezer-state", l, v, freezer_state_from_string, u->freezer_state))
|
||||
continue;
|
||||
|
||||
else if (streq(l, "markers")) {
|
||||
r = deserialize_markers(u, v);
|
||||
if (r < 0)
|
||||
log_unit_debug_errno(u, r, "Failed to deserialize \"%s=%s\", ignoring: %m", l, v);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if this is an IP accounting metric serialization field */
|
||||
m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v);
|
||||
else
|
||||
u->ip_accounting_extra[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IO accounting base value %s, ignoring.", v);
|
||||
else
|
||||
u->io_accounting_base[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IO accounting last value %s, ignoring.", v);
|
||||
else
|
||||
u->io_accounting_last[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unit_can_serialize(u)) {
|
||||
r = exec_runtime_deserialize_compat(u, l, v, fds);
|
||||
if (r < 0) {
|
||||
log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Returns positive if key was handled by the call */
|
||||
if (r > 0)
|
||||
continue;
|
||||
|
||||
r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
|
||||
if (r < 0)
|
||||
log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Versions before 228 did not carry a state change timestamp. In this case, take the current
|
||||
* time. This is useful, so that timeouts based on this timestamp don't trigger too early, and is
|
||||
* in-line with the logic from before 228 where the base for timeouts was not persistent across
|
||||
* reboots. */
|
||||
|
||||
if (!dual_timestamp_is_set(&u->state_change_timestamp))
|
||||
dual_timestamp_get(&u->state_change_timestamp);
|
||||
|
||||
/* Let's make sure that everything that is deserialized also gets any potential new cgroup settings
|
||||
* applied after we are done. For that we invalidate anything already realized, so that we can
|
||||
* realize it again. */
|
||||
unit_invalidate_cgroup(u, _CGROUP_MASK_ALL);
|
||||
unit_invalidate_cgroup_bpf(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_deserialize_skip(FILE *f) {
|
||||
int r;
|
||||
assert(f);
|
||||
|
||||
/* Skip serialized data for this unit. We don't know what it is. */
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
char *l;
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read serialization line: %m");
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
l = strstrip(line);
|
||||
|
||||
/* End marker */
|
||||
if (isempty(l))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) {
|
||||
const struct {
|
||||
UnitDependencyMask mask;
|
||||
const char *name;
|
||||
} table[] = {
|
||||
{ UNIT_DEPENDENCY_FILE, "file" },
|
||||
{ UNIT_DEPENDENCY_IMPLICIT, "implicit" },
|
||||
{ UNIT_DEPENDENCY_DEFAULT, "default" },
|
||||
{ UNIT_DEPENDENCY_UDEV, "udev" },
|
||||
{ UNIT_DEPENDENCY_PATH, "path" },
|
||||
{ UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" },
|
||||
{ UNIT_DEPENDENCY_MOUNTINFO_DEFAULT, "mountinfo-default" },
|
||||
{ UNIT_DEPENDENCY_PROC_SWAP, "proc-swap" },
|
||||
};
|
||||
|
||||
assert(f);
|
||||
assert(kind);
|
||||
assert(space);
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
|
||||
|
||||
if (mask == 0)
|
||||
break;
|
||||
|
||||
if (FLAGS_SET(mask, table[i].mask)) {
|
||||
if (*space)
|
||||
fputc(' ', f);
|
||||
else
|
||||
*space = true;
|
||||
|
||||
fputs(kind, f);
|
||||
fputs("-", f);
|
||||
fputs(table[i].name, f);
|
||||
|
||||
mask &= ~table[i].mask;
|
||||
}
|
||||
}
|
||||
|
||||
assert(mask == 0);
|
||||
}
|
||||
|
||||
void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
char *t, **j;
|
||||
const char *prefix2;
|
||||
char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX];
|
||||
Unit *following;
|
||||
_cleanup_set_free_ Set *following_set = NULL;
|
||||
CGroupMask m;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(u->type >= 0);
|
||||
|
||||
prefix = strempty(prefix);
|
||||
prefix2 = strjoina(prefix, "\t");
|
||||
|
||||
fprintf(f,
|
||||
"%s-> Unit %s:\n",
|
||||
prefix, u->id);
|
||||
|
||||
SET_FOREACH(t, u->aliases)
|
||||
fprintf(f, "%s\tAlias: %s\n", prefix, t);
|
||||
|
||||
fprintf(f,
|
||||
"%s\tDescription: %s\n"
|
||||
"%s\tInstance: %s\n"
|
||||
"%s\tUnit Load State: %s\n"
|
||||
"%s\tUnit Active State: %s\n"
|
||||
"%s\tState Change Timestamp: %s\n"
|
||||
"%s\tInactive Exit Timestamp: %s\n"
|
||||
"%s\tActive Enter Timestamp: %s\n"
|
||||
"%s\tActive Exit Timestamp: %s\n"
|
||||
"%s\tInactive Enter Timestamp: %s\n"
|
||||
"%s\tMay GC: %s\n"
|
||||
"%s\tNeed Daemon Reload: %s\n"
|
||||
"%s\tTransient: %s\n"
|
||||
"%s\tPerpetual: %s\n"
|
||||
"%s\tGarbage Collection Mode: %s\n"
|
||||
"%s\tSlice: %s\n"
|
||||
"%s\tCGroup: %s\n"
|
||||
"%s\tCGroup realized: %s\n",
|
||||
prefix, unit_description(u),
|
||||
prefix, strna(u->instance),
|
||||
prefix, unit_load_state_to_string(u->load_state),
|
||||
prefix, unit_active_state_to_string(unit_active_state(u)),
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->state_change_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[1], sizeof(timestamp[1]), u->inactive_exit_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[2], sizeof(timestamp[2]), u->active_enter_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[3], sizeof(timestamp[3]), u->active_exit_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[4], sizeof(timestamp[4]), u->inactive_enter_timestamp.realtime)),
|
||||
prefix, yes_no(unit_may_gc(u)),
|
||||
prefix, yes_no(unit_need_daemon_reload(u)),
|
||||
prefix, yes_no(u->transient),
|
||||
prefix, yes_no(u->perpetual),
|
||||
prefix, collect_mode_to_string(u->collect_mode),
|
||||
prefix, strna(unit_slice_name(u)),
|
||||
prefix, strna(u->cgroup_path),
|
||||
prefix, yes_no(u->cgroup_realized));
|
||||
|
||||
if (u->markers != 0) {
|
||||
fprintf(f, "%s\tMarkers:", prefix);
|
||||
|
||||
for (UnitMarker marker = 0; marker < _UNIT_MARKER_MAX; marker++)
|
||||
if (FLAGS_SET(u->markers, 1u << marker))
|
||||
fprintf(f, " %s", unit_marker_to_string(marker));
|
||||
fputs("\n", f);
|
||||
}
|
||||
|
||||
if (u->cgroup_realized_mask != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(u->cgroup_realized_mask, &s);
|
||||
fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
if (u->cgroup_enabled_mask != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(u->cgroup_enabled_mask, &s);
|
||||
fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_own_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_members_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_delegate_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup delegate mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
if (!sd_id128_is_null(u->invocation_id))
|
||||
fprintf(f, "%s\tInvocation ID: " SD_ID128_FORMAT_STR "\n",
|
||||
prefix, SD_ID128_FORMAT_VAL(u->invocation_id));
|
||||
|
||||
STRV_FOREACH(j, u->documentation)
|
||||
fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);
|
||||
|
||||
following = unit_following(u);
|
||||
if (following)
|
||||
fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
|
||||
|
||||
r = unit_following_set(u, &following_set);
|
||||
if (r >= 0) {
|
||||
Unit *other;
|
||||
|
||||
SET_FOREACH(other, following_set)
|
||||
fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id);
|
||||
}
|
||||
|
||||
if (u->fragment_path)
|
||||
fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
|
||||
|
||||
if (u->source_path)
|
||||
fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);
|
||||
|
||||
STRV_FOREACH(j, u->dropin_paths)
|
||||
fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
|
||||
|
||||
if (u->failure_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tFailure Action: %s\n", prefix, emergency_action_to_string(u->failure_action));
|
||||
if (u->failure_action_exit_status >= 0)
|
||||
fprintf(f, "%s\tFailure Action Exit Status: %i\n", prefix, u->failure_action_exit_status);
|
||||
if (u->success_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tSuccess Action: %s\n", prefix, emergency_action_to_string(u->success_action));
|
||||
if (u->success_action_exit_status >= 0)
|
||||
fprintf(f, "%s\tSuccess Action Exit Status: %i\n", prefix, u->success_action_exit_status);
|
||||
|
||||
if (u->job_timeout != USEC_INFINITY)
|
||||
fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
|
||||
|
||||
if (u->job_timeout_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action));
|
||||
|
||||
if (u->job_timeout_reboot_arg)
|
||||
fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
|
||||
|
||||
condition_dump_list(u->conditions, f, prefix, condition_type_to_string);
|
||||
condition_dump_list(u->asserts, f, prefix, assert_type_to_string);
|
||||
|
||||
if (dual_timestamp_is_set(&u->condition_timestamp))
|
||||
fprintf(f,
|
||||
"%s\tCondition Timestamp: %s\n"
|
||||
"%s\tCondition Result: %s\n",
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->condition_timestamp.realtime)),
|
||||
prefix, yes_no(u->condition_result));
|
||||
|
||||
if (dual_timestamp_is_set(&u->assert_timestamp))
|
||||
fprintf(f,
|
||||
"%s\tAssert Timestamp: %s\n"
|
||||
"%s\tAssert Result: %s\n",
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)),
|
||||
prefix, yes_no(u->assert_result));
|
||||
|
||||
for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
|
||||
UnitDependencyInfo di;
|
||||
Unit *other;
|
||||
|
||||
HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d]) {
|
||||
bool space = false;
|
||||
|
||||
fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id);
|
||||
|
||||
print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
|
||||
print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
|
||||
|
||||
fputs(")\n", f);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hashmap_isempty(u->requires_mounts_for)) {
|
||||
UnitDependencyInfo di;
|
||||
const char *path;
|
||||
|
||||
HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) {
|
||||
bool space = false;
|
||||
|
||||
fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path);
|
||||
|
||||
print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
|
||||
print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
|
||||
|
||||
fputs(")\n", f);
|
||||
}
|
||||
}
|
||||
|
||||
if (u->load_state == UNIT_LOADED) {
|
||||
|
||||
fprintf(f,
|
||||
"%s\tStopWhenUnneeded: %s\n"
|
||||
"%s\tRefuseManualStart: %s\n"
|
||||
"%s\tRefuseManualStop: %s\n"
|
||||
"%s\tDefaultDependencies: %s\n"
|
||||
"%s\tOnFailureJobMode: %s\n"
|
||||
"%s\tIgnoreOnIsolate: %s\n",
|
||||
prefix, yes_no(u->stop_when_unneeded),
|
||||
prefix, yes_no(u->refuse_manual_start),
|
||||
prefix, yes_no(u->refuse_manual_stop),
|
||||
prefix, yes_no(u->default_dependencies),
|
||||
prefix, job_mode_to_string(u->on_failure_job_mode),
|
||||
prefix, yes_no(u->ignore_on_isolate));
|
||||
|
||||
if (UNIT_VTABLE(u)->dump)
|
||||
UNIT_VTABLE(u)->dump(u, f, prefix2);
|
||||
|
||||
} else if (u->load_state == UNIT_MERGED)
|
||||
fprintf(f,
|
||||
"%s\tMerged into: %s\n",
|
||||
prefix, u->merged_into->id);
|
||||
else if (u->load_state == UNIT_ERROR)
|
||||
fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror_safe(u->load_error));
|
||||
|
||||
for (const char *n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track))
|
||||
fprintf(f, "%s\tBus Ref: %s\n", prefix, n);
|
||||
|
||||
if (u->job)
|
||||
job_dump(u->job, f, prefix2);
|
||||
|
||||
if (u->nop_job)
|
||||
job_dump(u->nop_job, f, prefix2);
|
||||
}
|
13
src/core/unit-serialize.h
Normal file
13
src/core/unit-serialize.h
Normal file
@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "unit.h"
|
||||
#include "fdset.h"
|
||||
|
||||
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
|
||||
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
|
||||
int unit_deserialize_skip(FILE *f);
|
||||
|
||||
void unit_dump(Unit *u, FILE *f, const char *prefix);
|
808
src/core/unit.c
808
src/core/unit.c
@ -26,8 +26,8 @@
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "id128-util.h"
|
||||
#include "io-util.h"
|
||||
#include "install.h"
|
||||
#include "io-util.h"
|
||||
#include "label.h"
|
||||
#include "load-dropin.h"
|
||||
#include "load-fragment.h"
|
||||
@ -35,11 +35,9 @@
|
||||
#include "macro.h"
|
||||
#include "missing_audit.h"
|
||||
#include "mkdir.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "serialize.h"
|
||||
#include "set.h"
|
||||
#include "signal-util.h"
|
||||
#include "sparse-endian.h"
|
||||
@ -1166,269 +1164,6 @@ const char *unit_status_string(Unit *u) {
|
||||
return unit_description(u);
|
||||
}
|
||||
|
||||
static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) {
|
||||
const struct {
|
||||
UnitDependencyMask mask;
|
||||
const char *name;
|
||||
} table[] = {
|
||||
{ UNIT_DEPENDENCY_FILE, "file" },
|
||||
{ UNIT_DEPENDENCY_IMPLICIT, "implicit" },
|
||||
{ UNIT_DEPENDENCY_DEFAULT, "default" },
|
||||
{ UNIT_DEPENDENCY_UDEV, "udev" },
|
||||
{ UNIT_DEPENDENCY_PATH, "path" },
|
||||
{ UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" },
|
||||
{ UNIT_DEPENDENCY_MOUNTINFO_DEFAULT, "mountinfo-default" },
|
||||
{ UNIT_DEPENDENCY_PROC_SWAP, "proc-swap" },
|
||||
};
|
||||
|
||||
assert(f);
|
||||
assert(kind);
|
||||
assert(space);
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
|
||||
|
||||
if (mask == 0)
|
||||
break;
|
||||
|
||||
if (FLAGS_SET(mask, table[i].mask)) {
|
||||
if (*space)
|
||||
fputc(' ', f);
|
||||
else
|
||||
*space = true;
|
||||
|
||||
fputs(kind, f);
|
||||
fputs("-", f);
|
||||
fputs(table[i].name, f);
|
||||
|
||||
mask &= ~table[i].mask;
|
||||
}
|
||||
}
|
||||
|
||||
assert(mask == 0);
|
||||
}
|
||||
|
||||
void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
char *t, **j;
|
||||
const char *prefix2;
|
||||
char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX];
|
||||
Unit *following;
|
||||
_cleanup_set_free_ Set *following_set = NULL;
|
||||
CGroupMask m;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(u->type >= 0);
|
||||
|
||||
prefix = strempty(prefix);
|
||||
prefix2 = strjoina(prefix, "\t");
|
||||
|
||||
fprintf(f,
|
||||
"%s-> Unit %s:\n",
|
||||
prefix, u->id);
|
||||
|
||||
SET_FOREACH(t, u->aliases)
|
||||
fprintf(f, "%s\tAlias: %s\n", prefix, t);
|
||||
|
||||
fprintf(f,
|
||||
"%s\tDescription: %s\n"
|
||||
"%s\tInstance: %s\n"
|
||||
"%s\tUnit Load State: %s\n"
|
||||
"%s\tUnit Active State: %s\n"
|
||||
"%s\tState Change Timestamp: %s\n"
|
||||
"%s\tInactive Exit Timestamp: %s\n"
|
||||
"%s\tActive Enter Timestamp: %s\n"
|
||||
"%s\tActive Exit Timestamp: %s\n"
|
||||
"%s\tInactive Enter Timestamp: %s\n"
|
||||
"%s\tMay GC: %s\n"
|
||||
"%s\tNeed Daemon Reload: %s\n"
|
||||
"%s\tTransient: %s\n"
|
||||
"%s\tPerpetual: %s\n"
|
||||
"%s\tGarbage Collection Mode: %s\n"
|
||||
"%s\tSlice: %s\n"
|
||||
"%s\tCGroup: %s\n"
|
||||
"%s\tCGroup realized: %s\n",
|
||||
prefix, unit_description(u),
|
||||
prefix, strna(u->instance),
|
||||
prefix, unit_load_state_to_string(u->load_state),
|
||||
prefix, unit_active_state_to_string(unit_active_state(u)),
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->state_change_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[1], sizeof(timestamp[1]), u->inactive_exit_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[2], sizeof(timestamp[2]), u->active_enter_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[3], sizeof(timestamp[3]), u->active_exit_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp[4], sizeof(timestamp[4]), u->inactive_enter_timestamp.realtime)),
|
||||
prefix, yes_no(unit_may_gc(u)),
|
||||
prefix, yes_no(unit_need_daemon_reload(u)),
|
||||
prefix, yes_no(u->transient),
|
||||
prefix, yes_no(u->perpetual),
|
||||
prefix, collect_mode_to_string(u->collect_mode),
|
||||
prefix, strna(unit_slice_name(u)),
|
||||
prefix, strna(u->cgroup_path),
|
||||
prefix, yes_no(u->cgroup_realized));
|
||||
|
||||
if (u->cgroup_realized_mask != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(u->cgroup_realized_mask, &s);
|
||||
fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
if (u->cgroup_enabled_mask != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(u->cgroup_enabled_mask, &s);
|
||||
fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_own_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_members_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
m = unit_get_delegate_mask(u);
|
||||
if (m != 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
(void) cg_mask_to_string(m, &s);
|
||||
fprintf(f, "%s\tCGroup delegate mask: %s\n", prefix, strnull(s));
|
||||
}
|
||||
|
||||
if (!sd_id128_is_null(u->invocation_id))
|
||||
fprintf(f, "%s\tInvocation ID: " SD_ID128_FORMAT_STR "\n",
|
||||
prefix, SD_ID128_FORMAT_VAL(u->invocation_id));
|
||||
|
||||
STRV_FOREACH(j, u->documentation)
|
||||
fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);
|
||||
|
||||
following = unit_following(u);
|
||||
if (following)
|
||||
fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
|
||||
|
||||
r = unit_following_set(u, &following_set);
|
||||
if (r >= 0) {
|
||||
Unit *other;
|
||||
|
||||
SET_FOREACH(other, following_set)
|
||||
fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id);
|
||||
}
|
||||
|
||||
if (u->fragment_path)
|
||||
fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
|
||||
|
||||
if (u->source_path)
|
||||
fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);
|
||||
|
||||
STRV_FOREACH(j, u->dropin_paths)
|
||||
fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
|
||||
|
||||
if (u->failure_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tFailure Action: %s\n", prefix, emergency_action_to_string(u->failure_action));
|
||||
if (u->failure_action_exit_status >= 0)
|
||||
fprintf(f, "%s\tFailure Action Exit Status: %i\n", prefix, u->failure_action_exit_status);
|
||||
if (u->success_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tSuccess Action: %s\n", prefix, emergency_action_to_string(u->success_action));
|
||||
if (u->success_action_exit_status >= 0)
|
||||
fprintf(f, "%s\tSuccess Action Exit Status: %i\n", prefix, u->success_action_exit_status);
|
||||
|
||||
if (u->job_timeout != USEC_INFINITY)
|
||||
fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
|
||||
|
||||
if (u->job_timeout_action != EMERGENCY_ACTION_NONE)
|
||||
fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action));
|
||||
|
||||
if (u->job_timeout_reboot_arg)
|
||||
fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
|
||||
|
||||
condition_dump_list(u->conditions, f, prefix, condition_type_to_string);
|
||||
condition_dump_list(u->asserts, f, prefix, assert_type_to_string);
|
||||
|
||||
if (dual_timestamp_is_set(&u->condition_timestamp))
|
||||
fprintf(f,
|
||||
"%s\tCondition Timestamp: %s\n"
|
||||
"%s\tCondition Result: %s\n",
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->condition_timestamp.realtime)),
|
||||
prefix, yes_no(u->condition_result));
|
||||
|
||||
if (dual_timestamp_is_set(&u->assert_timestamp))
|
||||
fprintf(f,
|
||||
"%s\tAssert Timestamp: %s\n"
|
||||
"%s\tAssert Result: %s\n",
|
||||
prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)),
|
||||
prefix, yes_no(u->assert_result));
|
||||
|
||||
for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
|
||||
UnitDependencyInfo di;
|
||||
Unit *other;
|
||||
|
||||
HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d]) {
|
||||
bool space = false;
|
||||
|
||||
fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id);
|
||||
|
||||
print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
|
||||
print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
|
||||
|
||||
fputs(")\n", f);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hashmap_isempty(u->requires_mounts_for)) {
|
||||
UnitDependencyInfo di;
|
||||
const char *path;
|
||||
|
||||
HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) {
|
||||
bool space = false;
|
||||
|
||||
fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path);
|
||||
|
||||
print_unit_dependency_mask(f, "origin", di.origin_mask, &space);
|
||||
print_unit_dependency_mask(f, "destination", di.destination_mask, &space);
|
||||
|
||||
fputs(")\n", f);
|
||||
}
|
||||
}
|
||||
|
||||
if (u->load_state == UNIT_LOADED) {
|
||||
|
||||
fprintf(f,
|
||||
"%s\tStopWhenUnneeded: %s\n"
|
||||
"%s\tRefuseManualStart: %s\n"
|
||||
"%s\tRefuseManualStop: %s\n"
|
||||
"%s\tDefaultDependencies: %s\n"
|
||||
"%s\tOnFailureJobMode: %s\n"
|
||||
"%s\tIgnoreOnIsolate: %s\n",
|
||||
prefix, yes_no(u->stop_when_unneeded),
|
||||
prefix, yes_no(u->refuse_manual_start),
|
||||
prefix, yes_no(u->refuse_manual_stop),
|
||||
prefix, yes_no(u->default_dependencies),
|
||||
prefix, job_mode_to_string(u->on_failure_job_mode),
|
||||
prefix, yes_no(u->ignore_on_isolate));
|
||||
|
||||
if (UNIT_VTABLE(u)->dump)
|
||||
UNIT_VTABLE(u)->dump(u, f, prefix2);
|
||||
|
||||
} else if (u->load_state == UNIT_MERGED)
|
||||
fprintf(f,
|
||||
"%s\tMerged into: %s\n",
|
||||
prefix, u->merged_into->id);
|
||||
else if (u->load_state == UNIT_ERROR)
|
||||
fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror_safe(u->load_error));
|
||||
|
||||
for (const char *n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track))
|
||||
fprintf(f, "%s\tBus Ref: %s\n", prefix, n);
|
||||
|
||||
if (u->job)
|
||||
job_dump(u->job, f, prefix2);
|
||||
|
||||
if (u->nop_job)
|
||||
job_dump(u->nop_job, f, prefix2);
|
||||
}
|
||||
|
||||
/* Common implementation for multiple backends */
|
||||
int unit_load_fragment_and_dropin(Unit *u, bool fragment_required) {
|
||||
int r;
|
||||
@ -2655,9 +2390,13 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
|
||||
|
||||
/* Make sure the cgroup and state files are always removed when we become inactive */
|
||||
if (UNIT_IS_INACTIVE_OR_FAILED(ns)) {
|
||||
SET_FLAG(u->markers,
|
||||
(1u << UNIT_MARKER_NEEDS_RELOAD)|(1u << UNIT_MARKER_NEEDS_RESTART),
|
||||
false);
|
||||
unit_prune_cgroup(u);
|
||||
unit_unlink_state_files(u);
|
||||
}
|
||||
} else if (ns != os && ns == UNIT_RELOADING)
|
||||
SET_FLAG(u->markers, 1u << UNIT_MARKER_NEEDS_RELOAD, false);
|
||||
|
||||
unit_update_on_console(u);
|
||||
|
||||
@ -3241,7 +2980,7 @@ char *unit_dbus_path_invocation_id(Unit *u) {
|
||||
return unit_dbus_path_from_name(u->invocation_id_string);
|
||||
}
|
||||
|
||||
static int unit_set_invocation_id(Unit *u, sd_id128_t id) {
|
||||
int unit_set_invocation_id(Unit *u, sd_id128_t id) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
@ -3526,539 +3265,6 @@ bool unit_can_serialize(Unit *u) {
|
||||
return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item;
|
||||
}
|
||||
|
||||
static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
assert(key);
|
||||
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
|
||||
r = cg_mask_to_string(mask, &s);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format cgroup mask: %m");
|
||||
|
||||
return serialize_item(f, key, s);
|
||||
}
|
||||
|
||||
static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes",
|
||||
[CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets",
|
||||
[CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes",
|
||||
[CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets",
|
||||
};
|
||||
|
||||
static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base",
|
||||
[CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base",
|
||||
};
|
||||
|
||||
static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last",
|
||||
[CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last",
|
||||
};
|
||||
|
||||
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
assert(fds);
|
||||
|
||||
if (unit_can_serialize(u)) {
|
||||
r = UNIT_VTABLE(u)->serialize(u, f, fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
(void) serialize_dual_timestamp(f, "state-change-timestamp", &u->state_change_timestamp);
|
||||
|
||||
(void) serialize_dual_timestamp(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "active-enter-timestamp", &u->active_enter_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "active-exit-timestamp", &u->active_exit_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
|
||||
|
||||
(void) serialize_dual_timestamp(f, "condition-timestamp", &u->condition_timestamp);
|
||||
(void) serialize_dual_timestamp(f, "assert-timestamp", &u->assert_timestamp);
|
||||
|
||||
if (dual_timestamp_is_set(&u->condition_timestamp))
|
||||
(void) serialize_bool(f, "condition-result", u->condition_result);
|
||||
|
||||
if (dual_timestamp_is_set(&u->assert_timestamp))
|
||||
(void) serialize_bool(f, "assert-result", u->assert_result);
|
||||
|
||||
(void) serialize_bool(f, "transient", u->transient);
|
||||
(void) serialize_bool(f, "in-audit", u->in_audit);
|
||||
|
||||
(void) serialize_bool(f, "exported-invocation-id", u->exported_invocation_id);
|
||||
(void) serialize_bool(f, "exported-log-level-max", u->exported_log_level_max);
|
||||
(void) serialize_bool(f, "exported-log-extra-fields", u->exported_log_extra_fields);
|
||||
(void) serialize_bool(f, "exported-log-rate-limit-interval", u->exported_log_ratelimit_interval);
|
||||
(void) serialize_bool(f, "exported-log-rate-limit-burst", u->exported_log_ratelimit_burst);
|
||||
|
||||
(void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base);
|
||||
if (u->cpu_usage_last != NSEC_INFINITY)
|
||||
(void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last);
|
||||
|
||||
if (u->managed_oom_kill_last > 0)
|
||||
(void) serialize_item_format(f, "managed-oom-kill-last", "%" PRIu64, u->managed_oom_kill_last);
|
||||
|
||||
if (u->oom_kill_last > 0)
|
||||
(void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last);
|
||||
|
||||
for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) {
|
||||
(void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]);
|
||||
|
||||
if (u->io_accounting_last[im] != UINT64_MAX)
|
||||
(void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]);
|
||||
}
|
||||
|
||||
if (u->cgroup_path)
|
||||
(void) serialize_item(f, "cgroup", u->cgroup_path);
|
||||
|
||||
(void) serialize_bool(f, "cgroup-realized", u->cgroup_realized);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask);
|
||||
(void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask);
|
||||
|
||||
if (uid_is_valid(u->ref_uid))
|
||||
(void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid);
|
||||
if (gid_is_valid(u->ref_gid))
|
||||
(void) serialize_item_format(f, "ref-gid", GID_FMT, u->ref_gid);
|
||||
|
||||
if (!sd_id128_is_null(u->invocation_id))
|
||||
(void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id));
|
||||
|
||||
(void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u)));
|
||||
|
||||
bus_track_serialize(u->bus_track, f, "ref");
|
||||
|
||||
for (CGroupIPAccountingMetric m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
|
||||
uint64_t v;
|
||||
|
||||
r = unit_get_ip_accounting(u, m, &v);
|
||||
if (r >= 0)
|
||||
(void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v);
|
||||
}
|
||||
|
||||
if (serialize_jobs) {
|
||||
if (u->job) {
|
||||
fputs("job\n", f);
|
||||
job_serialize(u->job, f);
|
||||
}
|
||||
|
||||
if (u->nop_job) {
|
||||
fputs("job\n", f);
|
||||
job_serialize(u->nop_job, f);
|
||||
}
|
||||
}
|
||||
|
||||
/* End marker */
|
||||
fputc('\n', f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unit_deserialize_job(Unit *u, FILE *f) {
|
||||
_cleanup_(job_freep) Job *j = NULL;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
|
||||
j = job_new_raw(u);
|
||||
if (!j)
|
||||
return log_oom();
|
||||
|
||||
r = job_deserialize(j, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = job_install_deserialized(j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(j);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(f);
|
||||
assert(fds);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
char *l, *v;
|
||||
ssize_t m;
|
||||
size_t k;
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read serialization line: %m");
|
||||
if (r == 0) /* eof */
|
||||
break;
|
||||
|
||||
l = strstrip(line);
|
||||
if (isempty(l)) /* End marker */
|
||||
break;
|
||||
|
||||
k = strcspn(l, "=");
|
||||
|
||||
if (l[k] == '=') {
|
||||
l[k] = 0;
|
||||
v = l+k+1;
|
||||
} else
|
||||
v = l+k;
|
||||
|
||||
if (streq(l, "job")) {
|
||||
if (v[0] == '\0') {
|
||||
/* New-style serialized job */
|
||||
r = unit_deserialize_job(u, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else /* Legacy for pre-44 */
|
||||
log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
|
||||
continue;
|
||||
} else if (streq(l, "state-change-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->state_change_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "inactive-exit-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->inactive_exit_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "active-enter-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->active_enter_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "active-exit-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->active_exit_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "inactive-enter-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->inactive_enter_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "condition-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->condition_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "assert-timestamp")) {
|
||||
(void) deserialize_dual_timestamp(v, &u->assert_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "condition-result")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse condition result value %s, ignoring.", v);
|
||||
else
|
||||
u->condition_result = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "assert-result")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse assert result value %s, ignoring.", v);
|
||||
else
|
||||
u->assert_result = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "transient")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse transient bool %s, ignoring.", v);
|
||||
else
|
||||
u->transient = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "in-audit")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse in-audit bool %s, ignoring.", v);
|
||||
else
|
||||
u->in_audit = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-invocation-id")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported invocation ID bool %s, ignoring.", v);
|
||||
else
|
||||
u->exported_invocation_id = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-level-max")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log level max bool %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_level_max = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-extra-fields")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log extra fields bool %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_extra_fields = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-rate-limit-interval")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log rate limit interval %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_ratelimit_interval = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "exported-log-rate-limit-burst")) {
|
||||
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse exported log rate limit burst %s, ignoring.", v);
|
||||
else
|
||||
u->exported_log_ratelimit_burst = r;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (STR_IN_SET(l, "cpu-usage-base", "cpuacct-usage-base")) {
|
||||
|
||||
r = safe_atou64(v, &u->cpu_usage_base);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse CPU usage base %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cpu-usage-last")) {
|
||||
|
||||
r = safe_atou64(v, &u->cpu_usage_last);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to read CPU usage last %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "managed-oom-kill-last")) {
|
||||
|
||||
r = safe_atou64(v, &u->managed_oom_kill_last);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to read managed OOM kill last %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "oom-kill-last")) {
|
||||
|
||||
r = safe_atou64(v, &u->oom_kill_last);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to read OOM kill last %s, ignoring.", v);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup")) {
|
||||
|
||||
r = unit_set_cgroup_path(u, v);
|
||||
if (r < 0)
|
||||
log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v);
|
||||
|
||||
(void) unit_watch_cgroup(u);
|
||||
(void) unit_watch_cgroup_memory(u);
|
||||
|
||||
continue;
|
||||
} else if (streq(l, "cgroup-realized")) {
|
||||
int b;
|
||||
|
||||
b = parse_boolean(v);
|
||||
if (b < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-realized bool %s, ignoring.", v);
|
||||
else
|
||||
u->cgroup_realized = b;
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup-realized-mask")) {
|
||||
|
||||
r = cg_mask_from_string(v, &u->cgroup_realized_mask);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-realized-mask %s, ignoring.", v);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup-enabled-mask")) {
|
||||
|
||||
r = cg_mask_from_string(v, &u->cgroup_enabled_mask);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-enabled-mask %s, ignoring.", v);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "cgroup-invalidated-mask")) {
|
||||
|
||||
r = cg_mask_from_string(v, &u->cgroup_invalidated_mask);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse cgroup-invalidated-mask %s, ignoring.", v);
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref-uid")) {
|
||||
uid_t uid;
|
||||
|
||||
r = parse_uid(v, &uid);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse referenced UID %s, ignoring.", v);
|
||||
else
|
||||
unit_ref_uid_gid(u, uid, GID_INVALID);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref-gid")) {
|
||||
gid_t gid;
|
||||
|
||||
r = parse_gid(v, &gid);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse referenced GID %s, ignoring.", v);
|
||||
else
|
||||
unit_ref_uid_gid(u, UID_INVALID, gid);
|
||||
|
||||
continue;
|
||||
|
||||
} else if (streq(l, "ref")) {
|
||||
|
||||
r = strv_extend(&u->deserialized_refs, v);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
continue;
|
||||
} else if (streq(l, "invocation-id")) {
|
||||
sd_id128_t id;
|
||||
|
||||
r = sd_id128_from_string(v, &id);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse invocation id %s, ignoring.", v);
|
||||
else {
|
||||
r = unit_set_invocation_id(u, id);
|
||||
if (r < 0)
|
||||
log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m");
|
||||
}
|
||||
|
||||
continue;
|
||||
} else if (streq(l, "freezer-state")) {
|
||||
FreezerState s;
|
||||
|
||||
s = freezer_state_from_string(v);
|
||||
if (s < 0)
|
||||
log_unit_debug(u, "Failed to deserialize freezer-state '%s', ignoring.", v);
|
||||
else
|
||||
u->freezer_state = s;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if this is an IP accounting metric serialization field */
|
||||
m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v);
|
||||
else
|
||||
u->ip_accounting_extra[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IO accounting base value %s, ignoring.", v);
|
||||
else
|
||||
u->io_accounting_base[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IO accounting last value %s, ignoring.", v);
|
||||
else
|
||||
u->io_accounting_last[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unit_can_serialize(u)) {
|
||||
r = exec_runtime_deserialize_compat(u, l, v, fds);
|
||||
if (r < 0) {
|
||||
log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Returns positive if key was handled by the call */
|
||||
if (r > 0)
|
||||
continue;
|
||||
|
||||
r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
|
||||
if (r < 0)
|
||||
log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Versions before 228 did not carry a state change timestamp. In this case, take the current time. This is
|
||||
* useful, so that timeouts based on this timestamp don't trigger too early, and is in-line with the logic from
|
||||
* before 228 where the base for timeouts was not persistent across reboots. */
|
||||
|
||||
if (!dual_timestamp_is_set(&u->state_change_timestamp))
|
||||
dual_timestamp_get(&u->state_change_timestamp);
|
||||
|
||||
/* Let's make sure that everything that is deserialized also gets any potential new cgroup settings applied
|
||||
* after we are done. For that we invalidate anything already realized, so that we can realize it again. */
|
||||
unit_invalidate_cgroup(u, _CGROUP_MASK_ALL);
|
||||
unit_invalidate_cgroup_bpf(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_deserialize_skip(FILE *f) {
|
||||
int r;
|
||||
assert(f);
|
||||
|
||||
/* Skip serialized data for this unit. We don't know what it is. */
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
char *l;
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read serialization line: %m");
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
l = strstrip(line);
|
||||
|
||||
/* End marker */
|
||||
if (isempty(l))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int unit_add_node_dependency(Unit *u, const char *what, UnitDependency dep, UnitDependencyMask mask) {
|
||||
_cleanup_free_ char *e = NULL;
|
||||
Unit *device;
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "bpf-program.h"
|
||||
#include "condition.h"
|
||||
#include "emergency-action.h"
|
||||
@ -118,9 +120,6 @@ typedef struct Unit {
|
||||
UnitLoadState load_state;
|
||||
Unit *merged_into;
|
||||
|
||||
FreezerState freezer_state;
|
||||
sd_bus_message *pending_freezer_message;
|
||||
|
||||
char *id; /* The one special name that we use for identification */
|
||||
char *instance;
|
||||
|
||||
@ -148,6 +147,16 @@ typedef struct Unit {
|
||||
/* If this is a transient unit we are currently writing, this is where we are writing it to */
|
||||
FILE *transient_file;
|
||||
|
||||
/* Freezer state */
|
||||
sd_bus_message *pending_freezer_message;
|
||||
FreezerState freezer_state;
|
||||
|
||||
/* Job timeout and action to take */
|
||||
EmergencyAction job_timeout_action;
|
||||
usec_t job_timeout;
|
||||
usec_t job_running_timeout;
|
||||
char *job_timeout_reboot_arg;
|
||||
|
||||
/* If there is something to do with this unit, then this is the installed job for it */
|
||||
Job *job;
|
||||
|
||||
@ -162,13 +171,6 @@ typedef struct Unit {
|
||||
sd_bus_track *bus_track;
|
||||
char **deserialized_refs;
|
||||
|
||||
/* Job timeout and action to take */
|
||||
usec_t job_timeout;
|
||||
usec_t job_running_timeout;
|
||||
bool job_running_timeout_set:1;
|
||||
EmergencyAction job_timeout_action;
|
||||
char *job_timeout_reboot_arg;
|
||||
|
||||
/* References to this */
|
||||
LIST_HEAD(UnitRef, refs_by_target);
|
||||
|
||||
@ -240,6 +242,9 @@ typedef struct Unit {
|
||||
RateLimit start_ratelimit;
|
||||
EmergencyAction start_limit_action;
|
||||
|
||||
/* The unit has been marked for reload, restart, etc. Stored as 1u << marker1 | 1u << marker2. */
|
||||
unsigned markers;
|
||||
|
||||
/* What to do on failure or success */
|
||||
EmergencyAction success_action, failure_action;
|
||||
int success_action_exit_status, failure_action_exit_status;
|
||||
@ -357,6 +362,8 @@ typedef struct Unit {
|
||||
|
||||
bool sent_dbus_new_signal:1;
|
||||
|
||||
bool job_running_timeout_set:1;
|
||||
|
||||
bool in_audit:1;
|
||||
bool on_console:1;
|
||||
|
||||
@ -721,8 +728,6 @@ int unit_freezer_state_kernel(Unit *u, FreezerState *ret);
|
||||
|
||||
const char* unit_sub_state_to_string(Unit *u);
|
||||
|
||||
void unit_dump(Unit *u, FILE *f, const char *prefix);
|
||||
|
||||
bool unit_can_reload(Unit *u) _pure_;
|
||||
bool unit_can_start(Unit *u) _pure_;
|
||||
bool unit_can_stop(Unit *u) _pure_;
|
||||
@ -764,10 +769,6 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
|
||||
|
||||
bool unit_can_serialize(Unit *u) _pure_;
|
||||
|
||||
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
|
||||
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
|
||||
int unit_deserialize_skip(FILE *f);
|
||||
|
||||
int unit_add_node_dependency(Unit *u, const char *what, UnitDependency d, UnitDependencyMask mask);
|
||||
int unit_add_blockdev_dependency(Unit *u, const char *what, UnitDependencyMask mask);
|
||||
|
||||
@ -847,6 +848,7 @@ void unit_unref_uid_gid(Unit *u, bool destroy_now);
|
||||
|
||||
void unit_notify_user_lookup(Unit *u, uid_t uid, gid_t gid);
|
||||
|
||||
int unit_set_invocation_id(Unit *u, sd_id128_t id);
|
||||
int unit_acquire_invocation_id(Unit *u);
|
||||
|
||||
bool unit_shall_confirm_spawn(Unit *u);
|
||||
|
@ -5587,17 +5587,26 @@ int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
|
||||
}
|
||||
|
||||
int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
|
||||
const char *s;
|
||||
char type;
|
||||
const char *contents, *s;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(l);
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', "s");
|
||||
r = sd_bus_message_peek_type(m, &type, &contents);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (type != SD_BUS_TYPE_ARRAY || !STR_IN_SET(contents, "s", "o", "g"))
|
||||
return -ENXIO;
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
while ((r = sd_bus_message_read_basic(m, 's', &s)) > 0) {
|
||||
/* sd_bus_message_read_basic() does content validation for us. */
|
||||
while ((r = sd_bus_message_read_basic(m, *contents, &s)) > 0) {
|
||||
r = strv_extend(l, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -297,8 +297,7 @@ static int client(struct context *c) {
|
||||
assert_se(r >= 0);
|
||||
assert_se(streq(s, "<<<hallo>>>"));
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
|
||||
assert_se(r < 0);
|
||||
@ -306,6 +305,12 @@ static int client(struct context *c) {
|
||||
|
||||
sd_bus_error_free(&error);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, NULL); /* NULL and "" are equivalent */
|
||||
assert_se(r < 0);
|
||||
assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
|
||||
|
||||
sd_bus_error_free(&error);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
|
||||
assert_se(r < 0);
|
||||
assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
|
||||
@ -319,8 +324,7 @@ static int client(struct context *c) {
|
||||
assert_se(r >= 0);
|
||||
assert_se(streq(s, "<<<hallo>>>"));
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
|
||||
assert_se(r >= 0);
|
||||
@ -332,8 +336,7 @@ static int client(struct context *c) {
|
||||
assert_se(r >= 0);
|
||||
assert_se(streq(s, "test"));
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
|
||||
assert_se(r >= 0);
|
||||
@ -352,8 +355,16 @@ static int client(struct context *c) {
|
||||
assert_se(r >= 0);
|
||||
fputs(s, stdout);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL); /* NULL and "" are equivalent */
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
fputs(s, stdout);
|
||||
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
|
||||
assert_se(r >= 0);
|
||||
@ -362,66 +373,60 @@ static int client(struct context *c) {
|
||||
assert_se(r >= 0);
|
||||
log_info("read %s", s);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
fputs(s, stdout);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
fputs(s, stdout);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &s);
|
||||
assert_se(r >= 0);
|
||||
fputs(s, stdout);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
|
||||
assert_se(r < 0);
|
||||
assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
|
||||
sd_bus_error_free(&error);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, NULL);
|
||||
assert_se(r < 0);
|
||||
assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
|
||||
sd_bus_error_free(&error);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_process(bus, &reply);
|
||||
@ -430,10 +435,9 @@ static int client(struct context *c) {
|
||||
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
|
||||
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_process(bus, &reply);
|
||||
@ -442,10 +446,9 @@ static int client(struct context *c) {
|
||||
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
|
||||
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_process(bus, &reply);
|
||||
@ -454,10 +457,9 @@ static int client(struct context *c) {
|
||||
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
|
||||
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_process(bus, &reply);
|
||||
@ -466,10 +468,9 @@ static int client(struct context *c) {
|
||||
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
|
||||
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_process(bus, &reply);
|
||||
@ -478,10 +479,9 @@ static int client(struct context *c) {
|
||||
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
|
||||
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_process(bus, &reply);
|
||||
@ -490,10 +490,9 @@ static int client(struct context *c) {
|
||||
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
|
||||
sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
reply = NULL;
|
||||
reply = sd_bus_message_unref(reply);
|
||||
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
|
||||
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
sd_bus_flush(bus);
|
||||
|
@ -82,7 +82,9 @@ fi \
|
||||
%{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_postun_with_restart}} \
|
||||
if [ $1 -ge 1 ] && [ -x @bindir@/systemctl ]; then \
|
||||
# Package upgrade, not uninstall \
|
||||
@bindir@/systemctl try-restart %{?*} || : \
|
||||
for unit in %{?*}; do \
|
||||
@bindir@/systemctl set-property $unit Markers=+needs-restart || : \
|
||||
done \
|
||||
fi \
|
||||
%{nil}
|
||||
|
18
src/rpm/meson.build
Normal file
18
src/rpm/meson.build
Normal file
@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
configure_file(
|
||||
input : 'macros.systemd.in',
|
||||
output : 'macros.systemd',
|
||||
configuration : substs,
|
||||
install_dir : rpmmacrosdir == 'no' ? '' : rpmmacrosdir)
|
||||
|
||||
# Those doesn't get installed anywhere, one of them needs to included in the
|
||||
# rpm spec file definition.
|
||||
configure_file(
|
||||
input : 'triggers.systemd.in',
|
||||
output : 'triggers.systemd',
|
||||
configuration : substs)
|
||||
configure_file(
|
||||
input : 'triggers.systemd.sh.in',
|
||||
output : 'triggers.systemd.sh',
|
||||
configuration : substs)
|
@ -6,14 +6,35 @@
|
||||
|
||||
# The contents of this are an example to be copied into systemd.spec.
|
||||
#
|
||||
# Minimum rpm version supported: 4.13.0
|
||||
# Minimum rpm version supported: 4.14.0
|
||||
|
||||
%transfiletriggerin -P 900900 -p <lua> -- @systemunitdir@ /etc/systemd/system
|
||||
-- This script will run after any package is initially installed or
|
||||
-- upgraded. We care about the case where a package is initially
|
||||
-- installed, because other cases are covered by the *un scriptlets,
|
||||
-- so sometimes we will reload needlessly.
|
||||
if posix.access("/run/systemd/system") then
|
||||
pid = posix.fork()
|
||||
if pid == 0 then
|
||||
assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
|
||||
elseif pid > 0 then
|
||||
posix.wait(pid)
|
||||
end
|
||||
|
||||
pid = posix.fork()
|
||||
if pid == 0 then
|
||||
assert(posix.exec("%{_bindir}/systemctl", "reload-or-restart", "--marked"))
|
||||
elseif pid > 0 then
|
||||
posix.wait(pid)
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerpostun -P 1000100 -p <lua> -- @systemunitdir@ /etc/systemd/system
|
||||
-- On removal, we need to run daemon-reload after any units have been
|
||||
-- removed.
|
||||
-- On upgrade, we need to run daemon-reload after any new unit files
|
||||
-- have been installed, but before %postun scripts in packages get
|
||||
-- executed.
|
||||
if posix.access("/run/systemd/system") then
|
||||
pid = posix.fork()
|
||||
if pid == 0 then
|
||||
@ -23,34 +44,12 @@ if posix.access("/run/systemd/system") then
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerun -p <lua> -- @systemunitdir@ /etc/systemd/system
|
||||
-- On removal, we need to run daemon-reload after any units have been
|
||||
-- removed. %transfiletriggerpostun would be ideal, but it does not get
|
||||
-- executed for some reason.
|
||||
-- On upgrade, we need to run daemon-reload after any new unit files
|
||||
-- have been installed, but before %postun scripts in packages get
|
||||
-- executed. %transfiletriggerun gets the right list of files
|
||||
-- but it is invoked too early (before changes happen).
|
||||
-- %filetriggerpostun happens at the right time, but it fires for
|
||||
-- every package.
|
||||
-- To execute the reload at the right time, we create a state
|
||||
-- file in %transfiletriggerun and execute the daemon-reload in
|
||||
-- the first %filetriggerpostun.
|
||||
|
||||
%transfiletriggerpostun -P 10000 -p <lua> -- @systemunitdir@ /etc/systemd/system
|
||||
-- We restart remaining services that should be restarted here.
|
||||
if posix.access("/run/systemd/system") then
|
||||
posix.mkdir("%{_localstatedir}/lib")
|
||||
posix.mkdir("%{_localstatedir}/lib/rpm-state")
|
||||
posix.mkdir("%{_localstatedir}/lib/rpm-state/systemd")
|
||||
io.open("%{_localstatedir}/lib/rpm-state/systemd/needs-reload", "w")
|
||||
end
|
||||
|
||||
%filetriggerpostun -P 1000100 -p <lua> -- @systemunitdir@ /etc/systemd/system
|
||||
if posix.access("%{_localstatedir}/lib/rpm-state/systemd/needs-reload") then
|
||||
posix.unlink("%{_localstatedir}/lib/rpm-state/systemd/needs-reload")
|
||||
posix.rmdir("%{_localstatedir}/lib/rpm-state/systemd")
|
||||
pid = posix.fork()
|
||||
if pid == 0 then
|
||||
assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
|
||||
assert(posix.exec("%{_bindir}/systemctl", "reload-or-restart", "--marked"))
|
||||
elseif pid > 0 then
|
||||
posix.wait(pid)
|
||||
end
|
||||
@ -69,7 +68,43 @@ if posix.access("/run/systemd/system") then
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerin -P 100500 -p <lua> -- @tmpfilesdir@
|
||||
%transfiletriggerin -P 1000700 udev -p <lua> -- @udevhwdbdir@
|
||||
-- This script will automatically invoke hwdb update if files have been
|
||||
-- installed or updated in @udevhwdbdir@.
|
||||
if posix.access("/run/systemd/system") then
|
||||
pid = posix.fork()
|
||||
if pid == 0 then
|
||||
assert(posix.exec("%{_bindir}/systemd-hwdb", "update"))
|
||||
elseif pid > 0 then
|
||||
posix.wait(pid)
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerin -P 1000700 -p <lua> -- @catalogdir@
|
||||
-- This script will automatically invoke journal catalog update if files
|
||||
-- have been installed or updated in @catalogdir@.
|
||||
if posix.access("/run/systemd/system") then
|
||||
pid = posix.fork()
|
||||
if pid == 0 then
|
||||
assert(posix.exec("%{_bindir}/journalctl", "--update-catalog"))
|
||||
elseif pid > 0 then
|
||||
posix.wait(pid)
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerin -P 1000700 -p <lua> -- @binfmtdir@
|
||||
-- This script will automatically apply binfmt rules if files have been
|
||||
-- installed or updated in @binfmtdir@.
|
||||
if posix.access("/run/systemd/system") then
|
||||
pid = posix.fork()
|
||||
if pid == 0 then
|
||||
assert(posix.exec("@rootlibexecdir@/systemd-binfmt"))
|
||||
elseif pid > 0 then
|
||||
posix.wait(pid)
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerin -P 1000600 -p <lua> -- @tmpfilesdir@
|
||||
-- This script will process files installed in @tmpfilesdir@ to create
|
||||
-- tmpfiles automatically. The priority is set such that it will run
|
||||
-- after the sysusers file trigger, but before any other triggers.
|
||||
@ -82,31 +117,7 @@ if posix.access("/run/systemd/system") then
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerin -p <lua> -- @udevhwdbdir@
|
||||
-- This script will automatically invoke hwdb update if files have been
|
||||
-- installed or updated in @udevhwdbdir@.
|
||||
if posix.access("/run/systemd/system") then
|
||||
pid = posix.fork()
|
||||
if pid == 0 then
|
||||
assert(posix.exec("%{_bindir}/systemd-hwdb", "update"))
|
||||
elseif pid > 0 then
|
||||
posix.wait(pid)
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerin -p <lua> -- @catalogdir@
|
||||
-- This script will automatically invoke journal catalog update if files
|
||||
-- have been installed or updated in @catalogdir@.
|
||||
if posix.access("/run/systemd/system") then
|
||||
pid = posix.fork()
|
||||
if pid == 0 then
|
||||
assert(posix.exec("%{_bindir}/journalctl", "--update-catalog"))
|
||||
elseif pid > 0 then
|
||||
posix.wait(pid)
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerin -p <lua> -- @udevrulesdir@
|
||||
%transfiletriggerin -P 1000600 udev -p <lua> -- @udevrulesdir@
|
||||
-- This script will automatically update udev with new rules if files
|
||||
-- have been installed or updated in @udevrulesdir@.
|
||||
if posix.access("/run/systemd/system") then
|
||||
@ -118,7 +129,7 @@ if posix.access("/run/systemd/system") then
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerin -p <lua> -- @sysctldir@
|
||||
%transfiletriggerin -P 1000500 -p <lua> -- @sysctldir@
|
||||
-- This script will automatically apply sysctl rules if files have been
|
||||
-- installed or updated in @sysctldir@.
|
||||
if posix.access("/run/systemd/system") then
|
||||
@ -129,15 +140,3 @@ if posix.access("/run/systemd/system") then
|
||||
posix.wait(pid)
|
||||
end
|
||||
end
|
||||
|
||||
%transfiletriggerin -p <lua> -- @binfmtdir@
|
||||
-- This script will automatically apply binfmt rules if files have been
|
||||
-- installed or updated in @binfmtdir@.
|
||||
if posix.access("/run/systemd/system") then
|
||||
pid = posix.fork()
|
||||
if pid == 0 then
|
||||
assert(posix.exec("@rootlibexecdir@/systemd-binfmt"))
|
||||
elseif pid > 0 then
|
||||
posix.wait(pid)
|
||||
end
|
||||
end
|
89
src/rpm/triggers.systemd.sh.in
Normal file
89
src/rpm/triggers.systemd.sh.in
Normal file
@ -0,0 +1,89 @@
|
||||
# -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# Copyright 2018 Neal Gompa
|
||||
|
||||
# The contents of this are an example to be copied into systemd.spec.
|
||||
#
|
||||
# Minimum rpm version supported: 4.14.0
|
||||
|
||||
%transfiletriggerin -P 900900 -- @systemunitdir@ /etc/systemd/system
|
||||
# This script will run after any package is initially installed or
|
||||
# upgraded. We care about the case where a package is initially
|
||||
# installed, because other cases are covered by the *un scriptlets,
|
||||
# so sometimes we will reload needlessly.
|
||||
if test -d "/run/systemd/system"; then
|
||||
%{_bindir}/systemctl daemon-reload || :
|
||||
%{_bindir}/systemctl reload-or-restart --marked || :
|
||||
fi
|
||||
|
||||
%transfiletriggerpostun -P 1000100 -- @systemunitdir@ /etc/systemd/system
|
||||
# On removal, we need to run daemon-reload after any units have been
|
||||
# removed.
|
||||
# On upgrade, we need to run daemon-reload after any new unit files
|
||||
# have been installed, but before %postun scripts in packages get
|
||||
# executed.
|
||||
if test -d "/run/systemd/system"; then
|
||||
%{_bindir}/systemctl daemon-reload || :
|
||||
fi
|
||||
|
||||
%transfiletriggerpostun -P 10000 -- @systemunitdir@ /etc/systemd/system
|
||||
# We restart remaining services that should be restarted here.
|
||||
if test -d "/run/systemd/system"; then
|
||||
%{_bindir}/systemctl reload-or-restart --marked || :
|
||||
fi
|
||||
|
||||
%transfiletriggerin -P 1000700 -- @sysusersdir@
|
||||
# This script will process files installed in @sysusersdir@ to create
|
||||
# specified users automatically. The priority is set such that it
|
||||
# will run before the tmpfiles file trigger.
|
||||
if test -d "/run/systemd/system"; then
|
||||
%{_bindir}/systemd-sysusers || :
|
||||
fi
|
||||
|
||||
%transfiletriggerin -P 1000700 udev -- @udevhwdbdir@
|
||||
# This script will automatically invoke hwdb update if files have been
|
||||
# installed or updated in @udevhwdbdir@.
|
||||
if test -d "/run/systemd/system"; then
|
||||
%{_bindir}/systemd-hwdb update || :
|
||||
fi
|
||||
|
||||
%transfiletriggerin -P 1000700 -- @catalogdir@
|
||||
# This script will automatically invoke journal catalog update if files
|
||||
# have been installed or updated in @catalogdir@.
|
||||
if test -d "/run/systemd/system"; then
|
||||
%{_bindir}/journalctl --update-catalog || :
|
||||
fi
|
||||
|
||||
%transfiletriggerin -P 1000700 -- @binfmtdir@
|
||||
# This script will automatically apply binfmt rules if files have been
|
||||
# installed or updated in @binfmtdir@.
|
||||
if test -d "/run/systemd/system"; then
|
||||
# systemd-binfmt might fail if binfmt_misc kernel module is not loaded
|
||||
# during install
|
||||
@rootlibexecdir@/systemd-binfmt || :
|
||||
fi
|
||||
|
||||
%transfiletriggerin -P 1000600 -- @tmpfilesdir@
|
||||
# This script will process files installed in @tmpfilesdir@ to create
|
||||
# tmpfiles automatically. The priority is set such that it will run
|
||||
# after the sysusers file trigger, but before any other triggers.
|
||||
if test -d "/run/systemd/system"; then
|
||||
%{_bindir}/systemd-tmpfiles --create || :
|
||||
fi
|
||||
|
||||
%transfiletriggerin -P 1000600 udev -- @udevrulesdir@
|
||||
# This script will automatically update udev with new rules if files
|
||||
# have been installed or updated in @udevrulesdir@.
|
||||
if test -e /run/udev/control; then
|
||||
%{_bindir}/udevadm control --reload || :
|
||||
fi
|
||||
|
||||
%transfiletriggerin -P 1000500 -- @sysctldir@
|
||||
# This script will automatically apply sysctl rules if files have been
|
||||
# installed or updated in @sysctldir@.
|
||||
if test -d "/run/systemd/system"; then
|
||||
@rootlibexecdir@/systemd-sysctl || :
|
||||
fi
|
@ -2192,7 +2192,8 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const
|
||||
|
||||
if (unit_dependency_from_string(field) >= 0 ||
|
||||
STR_IN_SET(field, "Documentation",
|
||||
"RequiresMountsFor"))
|
||||
"RequiresMountsFor",
|
||||
"Markers"))
|
||||
return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
|
||||
|
||||
t = condition_type_from_string(field);
|
||||
|
@ -14,7 +14,7 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int
|
||||
UnitActiveState active_state;
|
||||
sd_bus *bus;
|
||||
char **name;
|
||||
int r, i;
|
||||
int r;
|
||||
bool found = false;
|
||||
|
||||
r = acquire_bus(BUS_MANAGER, &bus);
|
||||
@ -33,7 +33,7 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int
|
||||
if (!arg_quiet)
|
||||
puts(unit_active_state_to_string(active_state));
|
||||
|
||||
for (i = 0; i < nb_states; ++i)
|
||||
for (int i = 0; i < nb_states; ++i)
|
||||
if (good_states[i] == active_state)
|
||||
found = true;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
static int show_installation_targets_client_side(const char *name) {
|
||||
UnitFileChange *changes = NULL;
|
||||
size_t n_changes = 0, i;
|
||||
size_t n_changes = 0;
|
||||
UnitFileFlags flags;
|
||||
char **p;
|
||||
int r;
|
||||
@ -22,7 +22,7 @@ static int show_installation_targets_client_side(const char *name) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get file links for %s: %m", name);
|
||||
|
||||
for (i = 0; i < n_changes; i++)
|
||||
for (size_t i = 0; i < n_changes; i++)
|
||||
if (changes[i].type == UNIT_FILE_UNLINK)
|
||||
printf(" %s\n", changes[i].path);
|
||||
|
||||
|
@ -12,11 +12,10 @@ static int list_dependencies_print(const char *name, int level, unsigned branche
|
||||
_cleanup_free_ char *n = NULL;
|
||||
size_t max_len = MAX(columns(),20u);
|
||||
size_t len = 0;
|
||||
int i;
|
||||
|
||||
if (!arg_plain) {
|
||||
|
||||
for (i = level - 1; i >= 0; i--) {
|
||||
for (int i = level - 1; i >= 0; i--) {
|
||||
len += 2;
|
||||
if (len > max_len - 3 && !arg_full) {
|
||||
printf("%s...\n",max_len % 2 ? "" : " ");
|
||||
|
@ -58,7 +58,6 @@ struct job_info {
|
||||
|
||||
static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
const struct job_info *j;
|
||||
const char *on, *off;
|
||||
int r;
|
||||
|
||||
@ -86,7 +85,7 @@ static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n
|
||||
|
||||
(void) table_set_empty_string(table, "-");
|
||||
|
||||
for (j = jobs; j < jobs + n; j++) {
|
||||
for (const struct job_info *j = jobs; j < jobs + n; j++) {
|
||||
if (streq(j->state, "running"))
|
||||
on = ansi_highlight();
|
||||
else
|
||||
|
@ -33,12 +33,10 @@ void machine_info_clear(struct machine_info *info) {
|
||||
}
|
||||
|
||||
static void free_machines_list(struct machine_info *machine_infos, int n) {
|
||||
int i;
|
||||
|
||||
if (!machine_infos)
|
||||
return;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
for (int i = 0; i < n; i++)
|
||||
machine_info_clear(&machine_infos[i]);
|
||||
|
||||
free(machine_infos);
|
||||
@ -150,7 +148,6 @@ static int get_machine_list(
|
||||
|
||||
static int output_machines_list(struct machine_info *machine_infos, unsigned n) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
struct machine_info *m;
|
||||
bool state_missing = false;
|
||||
int r;
|
||||
|
||||
@ -172,7 +169,7 @@ static int output_machines_list(struct machine_info *machine_infos, unsigned n)
|
||||
|
||||
(void) table_set_empty_string(table, "-");
|
||||
|
||||
for (m = machine_infos; m < machine_infos + n; m++) {
|
||||
for (struct machine_info *m = machine_infos; m < machine_infos + n; m++) {
|
||||
_cleanup_free_ char *mname = NULL;
|
||||
const char *on_state = "", *on_failed = "";
|
||||
bool circle = false;
|
||||
|
@ -136,7 +136,6 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) {
|
||||
int list_unit_files(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_free_ UnitFileList *units = NULL;
|
||||
UnitFileList *unit;
|
||||
size_t size = 0;
|
||||
unsigned c = 0;
|
||||
const char *state;
|
||||
@ -265,7 +264,7 @@ int list_unit_files(int argc, char *argv[], void *userdata) {
|
||||
return r;
|
||||
|
||||
if (install_client_side())
|
||||
for (unit = units; unit < units + c; unit++)
|
||||
for (UnitFileList *unit = units; unit < units + c; unit++)
|
||||
free(unit->path);
|
||||
|
||||
if (c == 0)
|
||||
|
@ -351,7 +351,6 @@ static int socket_info_compare(const struct socket_info *a, const struct socket_
|
||||
|
||||
static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
struct socket_info *s;
|
||||
const char *on, *off;
|
||||
int r;
|
||||
|
||||
@ -373,7 +372,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
|
||||
(void) table_set_empty_string(table, "-");
|
||||
|
||||
if (cs) {
|
||||
for (s = socket_infos; s < socket_infos + cs; s++) {
|
||||
for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) {
|
||||
_cleanup_free_ char *j = NULL;
|
||||
const char *path;
|
||||
|
||||
@ -432,8 +431,6 @@ int list_sockets(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_strv_free_ char **sockets_with_suffix = NULL;
|
||||
_cleanup_free_ UnitInfo *unit_infos = NULL;
|
||||
_cleanup_free_ struct socket_info *socket_infos = NULL;
|
||||
const UnitInfo *u;
|
||||
struct socket_info *s;
|
||||
unsigned cs = 0;
|
||||
size_t size = 0;
|
||||
int r, n;
|
||||
@ -454,9 +451,9 @@ int list_sockets(int argc, char *argv[], void *userdata) {
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
for (u = unit_infos; u < unit_infos + n; u++) {
|
||||
for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) {
|
||||
_cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
|
||||
int i, c;
|
||||
int c;
|
||||
|
||||
if (!endswith(u->id, ".socket"))
|
||||
continue;
|
||||
@ -476,7 +473,7 @@ int list_sockets(int argc, char *argv[], void *userdata) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < c; i++)
|
||||
for (int i = 0; i < c; i++)
|
||||
socket_infos[cs + i] = (struct socket_info) {
|
||||
.machine = u->machine,
|
||||
.id = u->id,
|
||||
@ -499,7 +496,7 @@ int list_sockets(int argc, char *argv[], void *userdata) {
|
||||
|
||||
cleanup:
|
||||
assert(cs == 0 || socket_infos);
|
||||
for (s = socket_infos; s < socket_infos + cs; s++) {
|
||||
for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) {
|
||||
free(s->type);
|
||||
free(s->path);
|
||||
if (s->own_triggered)
|
||||
@ -604,7 +601,6 @@ static int timer_info_compare(const struct timer_info *a, const struct timer_inf
|
||||
|
||||
static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
struct timer_info *t;
|
||||
const char *on, *off;
|
||||
int r;
|
||||
|
||||
@ -620,34 +616,34 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
|
||||
|
||||
(void) table_set_empty_string(table, "-");
|
||||
|
||||
if (n > 0) {
|
||||
for (t = timer_infos; t < timer_infos + n; t++) {
|
||||
_cleanup_free_ char *j = NULL, *activates = NULL;
|
||||
const char *unit;
|
||||
for (struct timer_info *t = timer_infos; t < timer_infos + n; t++) {
|
||||
_cleanup_free_ char *j = NULL, *activates = NULL;
|
||||
const char *unit;
|
||||
|
||||
if (t->machine) {
|
||||
j = strjoin(t->machine, ":", t->id);
|
||||
if (!j)
|
||||
return log_oom();
|
||||
unit = j;
|
||||
} else
|
||||
unit = t->id;
|
||||
|
||||
activates = strv_join(t->triggered, ", ");
|
||||
if (!activates)
|
||||
if (t->machine) {
|
||||
j = strjoin(t->machine, ":", t->id);
|
||||
if (!j)
|
||||
return log_oom();
|
||||
unit = j;
|
||||
} else
|
||||
unit = t->id;
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_TIMESTAMP, t->next_elapse,
|
||||
TABLE_TIMESTAMP_RELATIVE, t->next_elapse,
|
||||
TABLE_TIMESTAMP, t->last_trigger,
|
||||
TABLE_TIMESTAMP_RELATIVE, t->last_trigger,
|
||||
TABLE_STRING, unit,
|
||||
TABLE_STRING, activates);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
activates = strv_join(t->triggered, ", ");
|
||||
if (!activates)
|
||||
return log_oom();
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_TIMESTAMP, t->next_elapse,
|
||||
TABLE_TIMESTAMP_RELATIVE, t->next_elapse,
|
||||
TABLE_TIMESTAMP, t->last_trigger,
|
||||
TABLE_TIMESTAMP_RELATIVE, t->last_trigger,
|
||||
TABLE_STRING, unit,
|
||||
TABLE_STRING, activates);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
on = ansi_highlight();
|
||||
off = ansi_normal();
|
||||
} else {
|
||||
@ -699,8 +695,6 @@ int list_timers(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_strv_free_ char **timers_with_suffix = NULL;
|
||||
_cleanup_free_ struct timer_info *timer_infos = NULL;
|
||||
_cleanup_free_ UnitInfo *unit_infos = NULL;
|
||||
struct timer_info *t;
|
||||
const UnitInfo *u;
|
||||
size_t size = 0;
|
||||
int n, c = 0;
|
||||
dual_timestamp nw;
|
||||
@ -724,7 +718,7 @@ int list_timers(int argc, char *argv[], void *userdata) {
|
||||
|
||||
dual_timestamp_get(&nw);
|
||||
|
||||
for (u = unit_infos; u < unit_infos + n; u++) {
|
||||
for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) {
|
||||
_cleanup_strv_free_ char **triggered = NULL;
|
||||
dual_timestamp next = DUAL_TIMESTAMP_NULL;
|
||||
usec_t m, last = 0;
|
||||
@ -764,7 +758,7 @@ int list_timers(int argc, char *argv[], void *userdata) {
|
||||
output_timers_list(timer_infos, c);
|
||||
|
||||
cleanup:
|
||||
for (t = timer_infos; t < timer_infos + c; t++)
|
||||
for (struct timer_info *t = timer_infos; t < timer_infos + c; t++)
|
||||
strv_free(t->triggered);
|
||||
|
||||
return r;
|
||||
|
@ -1103,7 +1103,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||
|
||||
} else if (endswith(name, "ExitStatus") && streq(contents, "aiai")) {
|
||||
const int32_t *status, *signal;
|
||||
size_t n_status, n_signal, i;
|
||||
size_t n_status, n_signal;
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'r', "aiai");
|
||||
if (r < 0)
|
||||
@ -1132,7 +1132,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||
fputc('=', stdout);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_status; i++) {
|
||||
for (size_t i = 0; i < n_status; i++) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
@ -1141,7 +1141,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||
printf("%"PRIi32, status[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_signal; i++) {
|
||||
for (size_t i = 0; i < n_signal; i++) {
|
||||
const char *str;
|
||||
|
||||
str = signal_to_string((int) signal[i]);
|
||||
@ -1933,7 +1933,6 @@ static int show_all(
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_free_ UnitInfo *unit_infos = NULL;
|
||||
const UnitInfo *u;
|
||||
unsigned c;
|
||||
int r, ret = 0;
|
||||
|
||||
@ -1947,7 +1946,7 @@ static int show_all(
|
||||
|
||||
typesafe_qsort(unit_infos, c, unit_info_compare);
|
||||
|
||||
for (u = unit_infos; u < unit_infos + c; u++) {
|
||||
for (const UnitInfo *u = unit_infos; u < unit_infos + c; u++) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
p = unit_dbus_path_from_name(u->id);
|
||||
|
@ -36,9 +36,7 @@ static const struct {
|
||||
};
|
||||
|
||||
static const char *verb_to_method(const char *verb) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(unit_actions); i++)
|
||||
for (size_t i = 0; i < ELEMENTSOF(unit_actions); i++)
|
||||
if (streq_ptr(unit_actions[i].verb, verb))
|
||||
return unit_actions[i].method;
|
||||
|
||||
@ -46,9 +44,7 @@ static const char *verb_to_method(const char *verb) {
|
||||
}
|
||||
|
||||
static const char *verb_to_job_type(const char *verb) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(unit_actions); i++)
|
||||
for (size_t i = 0; i < ELEMENTSOF(unit_actions); i++)
|
||||
if (streq_ptr(unit_actions[i].verb, verb))
|
||||
return unit_actions[i].job_type;
|
||||
|
||||
@ -180,6 +176,43 @@ fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int enqueue_marked_jobs(
|
||||
sd_bus *bus,
|
||||
BusWaitForJobs *w) {
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
int r;
|
||||
|
||||
log_debug("%s dbus call org.freedesktop.systemd1.Manager EnqueueMarkedJobs()",
|
||||
arg_dry_run ? "Would execute" : "Executing");
|
||||
|
||||
if (arg_dry_run)
|
||||
return 0;
|
||||
|
||||
r = bus_call_method(bus, bus_systemd_mgr, "EnqueueMarkedJobs", &error, &reply, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to start jobs: %s", bus_error_message(&error, r));
|
||||
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
r = sd_bus_message_read_strv(reply, &paths);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
if (w) {
|
||||
char **path;
|
||||
|
||||
STRV_FOREACH(path, paths) {
|
||||
log_debug("Adding %s to the set", *path);
|
||||
r = bus_wait_for_jobs_add(w, *path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to watch job %s: %m", *path);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct action_metadata action_table[_ACTION_MAX] = {
|
||||
[ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
|
||||
[ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
|
||||
@ -200,9 +233,7 @@ const struct action_metadata action_table[_ACTION_MAX] = {
|
||||
};
|
||||
|
||||
enum action verb_to_action(const char *verb) {
|
||||
enum action i;
|
||||
|
||||
for (i = 0; i < _ACTION_MAX; i++)
|
||||
for (enum action i = 0; i < _ACTION_MAX; i++)
|
||||
if (streq_ptr(action_table[i].verb, verb))
|
||||
return i;
|
||||
|
||||
@ -271,7 +302,7 @@ int start_unit(int argc, char *argv[], void *userdata) {
|
||||
job_type = "start";
|
||||
mode = "isolate";
|
||||
suffix = ".target";
|
||||
} else {
|
||||
} else if (!arg_marked) {
|
||||
/* A command in style of "systemctl start <unit1> <unit2> …", "sysemctl stop <unit1> <unit2> …" and so on */
|
||||
method = verb_to_method(argv[0]);
|
||||
job_type = verb_to_job_type(argv[0]);
|
||||
@ -295,7 +326,7 @@ int start_unit(int argc, char *argv[], void *userdata) {
|
||||
names = strv_new(one_name);
|
||||
if (!names)
|
||||
return log_oom();
|
||||
} else {
|
||||
} else if (!arg_marked) {
|
||||
bool expanded;
|
||||
|
||||
r = expand_unit_names(bus, strv_skip(argv, 1), suffix, &names, &expanded);
|
||||
@ -328,19 +359,23 @@ int start_unit(int argc, char *argv[], void *userdata) {
|
||||
return log_error_errno(r, "Failed to allocate unit watch context: %m");
|
||||
}
|
||||
|
||||
STRV_FOREACH(name, names) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
if (arg_marked)
|
||||
ret = enqueue_marked_jobs(bus, w);
|
||||
|
||||
r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu);
|
||||
if (ret == EXIT_SUCCESS && r < 0)
|
||||
ret = translate_bus_error_to_exit_status(r, &error);
|
||||
else
|
||||
STRV_FOREACH(name, names) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
if (r >= 0 && streq(method, "StopUnit")) {
|
||||
r = strv_push(&stopped_units, *name);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu);
|
||||
if (ret == EXIT_SUCCESS && r < 0)
|
||||
ret = translate_bus_error_to_exit_status(r, &error);
|
||||
|
||||
if (r >= 0 && streq(method, "StopUnit")) {
|
||||
r = strv_push(&stopped_units, *name);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!arg_no_block) {
|
||||
const char* extra_args[4];
|
||||
|
@ -62,9 +62,7 @@ int acquire_bus(BusFocus focus, sd_bus **ret) {
|
||||
}
|
||||
|
||||
void release_busses(void) {
|
||||
BusFocus w;
|
||||
|
||||
for (w = 0; w < _BUS_FOCUS_MAX; w++)
|
||||
for (BusFocus w = 0; w < _BUS_FOCUS_MAX; w++)
|
||||
buses[w] = sd_bus_flush_close_unref(buses[w]);
|
||||
}
|
||||
|
||||
@ -237,7 +235,7 @@ int get_unit_list(
|
||||
int expand_unit_names(sd_bus *bus, char **names, const char* suffix, char ***ret, bool *ret_expanded) {
|
||||
_cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
|
||||
char **name;
|
||||
int r, i;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(ret);
|
||||
@ -272,7 +270,7 @@ int expand_unit_names(sd_bus *bus, char **names, const char* suffix, char ***ret
|
||||
n = strv_length(mangled);
|
||||
allocated = n + 1;
|
||||
|
||||
for (i = 0; i < r; i++) {
|
||||
for (int i = 0; i < r; i++) {
|
||||
if (!GREEDY_REALLOC(mangled, allocated, n+2))
|
||||
return log_oom();
|
||||
|
||||
|
@ -109,6 +109,7 @@ char **arg_clean_what = NULL;
|
||||
TimestampStyle arg_timestamp_style = TIMESTAMP_PRETTY;
|
||||
bool arg_read_only = false;
|
||||
bool arg_mkdir = false;
|
||||
bool arg_marked = false;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
@ -296,6 +297,7 @@ static int systemctl_help(void) {
|
||||
" 'us+utc': 'Day YYYY-MM-DD HH:MM:SS.UUUUUU UTC\n"
|
||||
" --read-only Create read-only bind mount\n"
|
||||
" --mkdir Create directory before mounting, if missing\n"
|
||||
" --marked Restart/reload previously marked units\n"
|
||||
"\nSee the %2$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
link,
|
||||
@ -414,6 +416,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
ARG_TIMESTAMP_STYLE,
|
||||
ARG_READ_ONLY,
|
||||
ARG_MKDIR,
|
||||
ARG_MARKED,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -472,6 +475,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
{ "timestamp", required_argument, NULL, ARG_TIMESTAMP_STYLE },
|
||||
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
|
||||
{ "mkdir", no_argument, NULL, ARG_MKDIR },
|
||||
{ "marked", no_argument, NULL, ARG_MARKED },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -882,6 +886,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
arg_mkdir = true;
|
||||
break;
|
||||
|
||||
case ARG_MARKED:
|
||||
arg_marked = true;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
/* Output an error mimicking getopt, and print a hint afterwards */
|
||||
log_error("%s: invalid option -- '.'", program_invocation_name);
|
||||
@ -905,6 +913,27 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--wait may not be combined with --no-block.");
|
||||
|
||||
bool do_reload_or_restart = streq_ptr(argv[optind], "reload-or-restart");
|
||||
if (arg_marked) {
|
||||
if (!do_reload_or_restart)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--marked may only be used with 'reload-or-restart'.");
|
||||
if (optind + 1 < argc)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"No additional arguments allowed with 'reload-or-restart --marked'.");
|
||||
if (arg_wait)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--marked --wait is not supported.");
|
||||
if (arg_show_transaction)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--marked --show-transaction is not supported.");
|
||||
|
||||
} else if (do_reload_or_restart) {
|
||||
if (optind + 1 >= argc)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"List of units to restart/reload is required.");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -982,7 +1011,7 @@ static int systemctl_main(int argc, char *argv[]) {
|
||||
{ "reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
|
||||
{ "restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
|
||||
{ "try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
|
||||
{ "reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
|
||||
{ "reload-or-restart", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
|
||||
{ "reload-or-try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with old systemctl <= 228 */
|
||||
{ "try-reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
|
||||
{ "force-reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with SysV */
|
||||
|
@ -93,5 +93,6 @@ extern char **arg_clean_what;
|
||||
extern TimestampStyle arg_timestamp_style;
|
||||
extern bool arg_read_only;
|
||||
extern bool arg_mkdir;
|
||||
extern bool arg_marked;
|
||||
|
||||
int systemctl_dispatch_parse_argv(int argc, char *argv[]);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "rm-rf.h"
|
||||
#include "service.h"
|
||||
#include "tests.h"
|
||||
#include "unit.h"
|
||||
#include "unit-serialize.h"
|
||||
#include "virt.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
static void test_udev_builtin_cmd_to_ptr(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
/* Those could have been static_assert()s, but ({}) is not allowed there. */
|
||||
/* Those could have been static asserts, but ({}) is not allowed there. */
|
||||
#if HAVE_BLKID
|
||||
assert_se(UDEV_BUILTIN_CMD_TO_PTR(UDEV_BUILTIN_BLKID));
|
||||
assert_se(PTR_TO_UDEV_BUILTIN_CMD(UDEV_BUILTIN_CMD_TO_PTR(UDEV_BUILTIN_BLKID)) == UDEV_BUILTIN_BLKID);
|
||||
|
Loading…
Reference in New Issue
Block a user