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

Compare commits

..

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

14 changed files with 34 additions and 252 deletions

View File

@ -2644,33 +2644,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
</para> </para>
<para><varname>Markers</varname> is an array of string flags that can be set using <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. <function>SetUnitProperties()</function> to indicate that the service should be reloaded or
Currently known values are <literal>needs-restart</literal>, <literal>needs-stop</literal>, restarted. Currently known values are <literal>needs-restart</literal> and
<literal>needs-start</literal> and <literal>needs-reload</literal>. Package scripts may use the first <literal>needs-reload</literal>. Package scripts may use the first to mark units for later restart when
three to mark units for later restart or start or stop when a new version of the package is installed a new version of the package is installed. Configuration management scripts may use the second to mark
or removed. Configuration management scripts may use the fourth to mark units for a later reload when units for a later reload when the configuration is adjusted. Those flags are not set by the manager,
the configuration is adjusted. Those flags are not set by the manager, except to unset as appropriate except to unset as appropriate when the unit is stopped, restarted, or reloaded.</para>
when the unit is stopped, restarted, or reloaded. When markers are set, they are normalized according
to the following precedence rules, modeled after the job type merging logic. When new markers are
applied incrementally (using the <literal>+</literal> prefix), conflicting existing markers are
cleared before the new markers are merged in:
<itemizedlist>
<listitem><para><literal>needs-reload</literal> loses against all other markers. If any of
<literal>needs-restart</literal>, <literal>needs-start</literal>, or <literal>needs-stop</literal>
is set, <literal>needs-reload</literal> is cleared.</para></listitem>
<listitem><para><literal>needs-stop</literal> wins against <literal>needs-restart</literal> and
<literal>needs-reload</literal>, clearing both.</para></listitem>
<listitem><para><literal>needs-start</literal> wins against <literal>needs-stop</literal>, clearing
it.</para></listitem>
<listitem><para><literal>needs-restart</literal> wins against <literal>needs-start</literal>. If
both are set, <literal>needs-start</literal> is cleared.</para></listitem>
</itemizedlist>
For example, if a unit currently has <literal>needs-stop</literal> set and a new
<literal>+needs-start</literal> marker is applied, the existing <literal>needs-stop</literal> is
cleared and only <literal>needs-start</literal> remains. Conversely, applying
<literal>+needs-stop</literal> to any existing marker will clear all other markers, as
<literal>needs-stop</literal> takes precedence over <literal>needs-restart</literal> and
<literal>needs-reload</literal>, and the new marker clears conflicting existing ones.</para>
<para><varname>JobTimeoutUSec</varname> maps directly to the corresponding configuration setting in the <para><varname>JobTimeoutUSec</varname> maps directly to the corresponding configuration setting in the
unit file.</para> unit file.</para>

View File

@ -2855,10 +2855,10 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<varlistentry> <varlistentry>
<term><option>--marked</option></term> <term><option>--marked</option></term>
<listitem><para>Only allowed with <command>reload-or-restart</command>, <command>start</command>, or <listitem><para>Only allowed with <command>reload-or-restart</command>. Enqueues restart jobs for all
<command>stop</command>. Enqueues jobs for all units that are marked. When a unit marked for reload units that have the <literal>needs-restart</literal> mark, and reload jobs for units that have the
does not support reload, restart will be queued. Those properties can be set using <literal>needs-reload</literal> mark. When a unit marked for reload does not support reload, restart
<command>set-property Markers=…</command>.</para> will be queued. Those properties can be set using <command>set-property Markers=…</command>.</para>
<para>Unless <option>--no-block</option> is used, <command>systemctl</command> will wait for the <para>Unless <option>--no-block</option> is used, <command>systemctl</command> will wait for the
queued jobs to finish.</para> queued jobs to finish.</para>

View File

@ -9,5 +9,5 @@ Environment=
GIT_URL=https://salsa.debian.org/systemd-team/systemd.git GIT_URL=https://salsa.debian.org/systemd-team/systemd.git
GIT_SUBDIR=debian GIT_SUBDIR=debian
GIT_BRANCH=debian/master GIT_BRANCH=debian/master
GIT_COMMIT=89a825b80ee85e58b530cd95438988a6fb3531a3 GIT_COMMIT=ecec6127927ca59726e3d3535a2b2344f585cf74
PKG_SUBDIR=debian PKG_SUBDIR=debian

View File

@ -155,8 +155,6 @@ FreezerState freezer_state_objective(FreezerState state) {
static const char* const unit_marker_table[_UNIT_MARKER_MAX] = { static const char* const unit_marker_table[_UNIT_MARKER_MAX] = {
[UNIT_MARKER_NEEDS_RELOAD] = "needs-reload", [UNIT_MARKER_NEEDS_RELOAD] = "needs-reload",
[UNIT_MARKER_NEEDS_RESTART] = "needs-restart", [UNIT_MARKER_NEEDS_RESTART] = "needs-restart",
[UNIT_MARKER_NEEDS_STOP] = "needs-stop",
[UNIT_MARKER_NEEDS_START] = "needs-start",
}; };
DEFINE_STRING_TABLE_LOOKUP(unit_marker, UnitMarker); DEFINE_STRING_TABLE_LOOKUP(unit_marker, UnitMarker);

View File

@ -62,8 +62,6 @@ typedef enum FreezerState {
typedef enum UnitMarker { typedef enum UnitMarker {
UNIT_MARKER_NEEDS_RELOAD, UNIT_MARKER_NEEDS_RELOAD,
UNIT_MARKER_NEEDS_RESTART, UNIT_MARKER_NEEDS_RESTART,
UNIT_MARKER_NEEDS_STOP,
UNIT_MARKER_NEEDS_START,
_UNIT_MARKER_MAX, _UNIT_MARKER_MAX,
_UNIT_MARKER_INVALID = -EINVAL, _UNIT_MARKER_INVALID = -EINVAL,
} UnitMarker; } UnitMarker;

View File

@ -2132,26 +2132,17 @@ static int method_enqueue_marked_jobs(sd_bus_message *message, void *userdata, s
continue; continue;
BusUnitQueueFlags flags; BusUnitQueueFlags flags;
JobType job; if (BIT_SET(u->markers, UNIT_MARKER_NEEDS_RESTART))
if (BIT_SET(u->markers, UNIT_MARKER_NEEDS_RESTART)) {
flags = 0; flags = 0;
job = JOB_TRY_RESTART; else if (BIT_SET(u->markers, UNIT_MARKER_NEEDS_RELOAD))
} else if (BIT_SET(u->markers, UNIT_MARKER_NEEDS_RELOAD)) {
flags = BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE; flags = BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
job = JOB_TRY_RESTART; else
} else if (BIT_SET(u->markers, UNIT_MARKER_NEEDS_STOP)) {
flags = 0;
job = JOB_STOP;
} else if (BIT_SET(u->markers, UNIT_MARKER_NEEDS_START)) {
flags = 0;
job = JOB_START;
} else
continue; continue;
r = mac_selinux_unit_access_check(u, message, job_type_to_access_method(job), &error); r = mac_selinux_unit_access_check(u, message, "start", &error);
if (r >= 0) if (r >= 0)
r = bus_unit_queue_job_one(message, u, r = bus_unit_queue_job_one(message, u,
job, JOB_FAIL, flags, JOB_TRY_RESTART, JOB_FAIL, flags,
reply, &error); reply, &error);
if (ERRNO_IS_NEG_RESOURCE(r)) if (ERRNO_IS_NEG_RESOURCE(r))
return r; return r;

View File

@ -2151,8 +2151,9 @@ static int bus_unit_set_live_property(
if (!UNIT_WRITE_FLAGS_NOOP(flags)) { if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (some_absolute) if (some_absolute)
mask = UINT_MAX; u->markers = settings;
u->markers = unit_normalize_markers((u->markers & ~mask), settings); else
u->markers = settings | (u->markers & ~mask);
} }
return 1; return 1;

View File

@ -11,7 +11,6 @@
#include "all-units.h" #include "all-units.h"
#include "alloc-util.h" #include "alloc-util.h"
#include "ansi-color.h" #include "ansi-color.h"
#include "bitfield.h"
#include "bpf-restrict-fs.h" #include "bpf-restrict-fs.h"
#include "bus-common-errors.h" #include "bus-common-errors.h"
#include "bus-internal.h" #include "bus-internal.h"
@ -480,9 +479,6 @@ bool unit_may_gc(Unit *u) {
if (r <= 0 && !IN_SET(r, -ENXIO, -EOWNERDEAD)) if (r <= 0 && !IN_SET(r, -ENXIO, -EOWNERDEAD))
return false; /* ENXIO/EOWNERDEAD means: currently not realized */ return false; /* ENXIO/EOWNERDEAD means: currently not realized */
if (unit_can_start(u) && BIT_SET(u->markers, UNIT_MARKER_NEEDS_START))
return false;
if (!UNIT_VTABLE(u)->may_gc) if (!UNIT_VTABLE(u)->may_gc)
return true; return true;
@ -2762,13 +2758,11 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
/* Make sure the cgroup and state files are always removed when we become inactive */ /* Make sure the cgroup and state files are always removed when we become inactive */
if (UNIT_IS_INACTIVE_OR_FAILED(ns)) { if (UNIT_IS_INACTIVE_OR_FAILED(ns)) {
SET_FLAG(u->markers, SET_FLAG(u->markers,
(1u << UNIT_MARKER_NEEDS_RELOAD)|(1u << UNIT_MARKER_NEEDS_RESTART)|(1u << UNIT_MARKER_NEEDS_STOP), (1u << UNIT_MARKER_NEEDS_RELOAD)|(1u << UNIT_MARKER_NEEDS_RESTART),
false); false);
unit_prune_cgroup(u); unit_prune_cgroup(u);
unit_unlink_state_files(u); unit_unlink_state_files(u);
} else if (UNIT_IS_ACTIVE_OR_ACTIVATING(ns)) } else if (ns != os && ns == UNIT_RELOADING)
SET_FLAG(u->markers, 1u << UNIT_MARKER_NEEDS_START, false);
else if (ns != os && ns == UNIT_RELOADING)
SET_FLAG(u->markers, 1u << UNIT_MARKER_NEEDS_RELOAD, false); SET_FLAG(u->markers, 1u << UNIT_MARKER_NEEDS_RELOAD, false);
unit_update_on_console(u); unit_update_on_console(u);
@ -7092,45 +7086,8 @@ int parse_unit_marker(const char *marker, unsigned *settings, unsigned *mask) {
if (m < 0) if (m < 0)
return -EINVAL; return -EINVAL;
/* When +- are not used, last one wins, so reset the bitmask before storing the new result */
if (!some_plus_minus)
*settings = 0;
SET_FLAG(*settings, 1u << m, b); SET_FLAG(*settings, 1u << m, b);
SET_FLAG(*mask, 1u << m, true); SET_FLAG(*mask, 1u << m, true);
return some_plus_minus; return some_plus_minus;
} }
unsigned unit_normalize_markers(unsigned existing_markers, unsigned new_markers) {
/* Follow the job merging logic: when new markers conflict with existing ones, the new marker
* takes precedence and clears out conflicting existing markers. Then standard normalization
* resolves any remaining conflicts. */
/* New stop wins against all existing markers */
if (BIT_SET(new_markers, UNIT_MARKER_NEEDS_STOP))
CLEAR_BITS(existing_markers, UNIT_MARKER_NEEDS_RESTART, UNIT_MARKER_NEEDS_START, UNIT_MARKER_NEEDS_RELOAD);
/* New start wins against existing stop */
if (BIT_SET(new_markers, UNIT_MARKER_NEEDS_START))
CLEAR_BIT(existing_markers, UNIT_MARKER_NEEDS_STOP);
/* New restart wins against existing start and reload */
if (BIT_SET(new_markers, UNIT_MARKER_NEEDS_RESTART))
CLEAR_BITS(existing_markers, UNIT_MARKER_NEEDS_START, UNIT_MARKER_NEEDS_RELOAD);
unsigned markers = existing_markers | new_markers;
/* Standard normalization: reload loses against everything */
if (BIT_SET(markers, UNIT_MARKER_NEEDS_RESTART) || BIT_SET(markers, UNIT_MARKER_NEEDS_START) || BIT_SET(markers, UNIT_MARKER_NEEDS_STOP))
CLEAR_BIT(markers, UNIT_MARKER_NEEDS_RELOAD);
/* Stop wins against restart and reload */
if (BIT_SET(markers, UNIT_MARKER_NEEDS_STOP))
CLEAR_BITS(markers, UNIT_MARKER_NEEDS_RESTART, UNIT_MARKER_NEEDS_RELOAD);
/* Start wins against stop */
if (BIT_SET(markers, UNIT_MARKER_NEEDS_START))
CLEAR_BIT(markers, UNIT_MARKER_NEEDS_STOP);
/* Restart wins against start */
if (BITS_SET(markers, UNIT_MARKER_NEEDS_RESTART, UNIT_MARKER_NEEDS_START))
CLEAR_BIT(markers, UNIT_MARKER_NEEDS_START);
return markers;
}

View File

@ -1095,7 +1095,6 @@ DECLARE_STRING_TABLE_LOOKUP(oom_policy, OOMPolicy);
int unit_queue_job_check_and_mangle_type(Unit *u, JobType *type, bool reload_if_possible, sd_bus_error *reterr_error); int unit_queue_job_check_and_mangle_type(Unit *u, JobType *type, bool reload_if_possible, sd_bus_error *reterr_error);
int parse_unit_marker(const char *marker, unsigned *settings, unsigned *mask); int parse_unit_marker(const char *marker, unsigned *settings, unsigned *mask);
unsigned unit_normalize_markers(unsigned existing_markers, unsigned new_markers);
/* Macros which append UNIT= or USER_UNIT= to the message */ /* Macros which append UNIT= or USER_UNIT= to the message */

View File

@ -343,7 +343,6 @@ int vl_method_enqueue_marked_jobs_manager(sd_varlink *link, sd_json_variant *par
_cleanup_(sd_bus_error_free) sd_bus_error bus_error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_error_free) sd_bus_error bus_error = SD_BUS_ERROR_NULL;
const char *error_id = NULL; const char *error_id = NULL;
uint32_t job_id = 0; /* silence 'maybe-uninitialized' compiler warning */ uint32_t job_id = 0; /* silence 'maybe-uninitialized' compiler warning */
JobType job;
/* ignore aliases */ /* ignore aliases */
if (u->id != k) if (u->id != k)
@ -351,20 +350,14 @@ int vl_method_enqueue_marked_jobs_manager(sd_varlink *link, sd_json_variant *par
if (u->markers == 0) if (u->markers == 0)
continue; continue;
if (BIT_SET(u->markers, UNIT_MARKER_NEEDS_STOP))
job = JOB_STOP;
else if (BIT_SET(u->markers, UNIT_MARKER_NEEDS_START))
job = JOB_START;
else
job = JOB_TRY_RESTART;
r = mac_selinux_unit_access_check_varlink(u, link, job_type_to_access_method(job)); r = mac_selinux_unit_access_check_varlink(u, link, job_type_to_access_method(JOB_TRY_RESTART));
if (r < 0) if (r < 0)
error_id = SD_VARLINK_ERROR_PERMISSION_DENIED; error_id = SD_VARLINK_ERROR_PERMISSION_DENIED;
else else
r = varlink_unit_queue_job_one( r = varlink_unit_queue_job_one(
u, u,
job, JOB_TRY_RESTART,
JOB_FAIL, JOB_FAIL,
/* reload_if_possible= */ !BIT_SET(u->markers, UNIT_MARKER_NEEDS_RESTART), /* reload_if_possible= */ !BIT_SET(u->markers, UNIT_MARKER_NEEDS_RESTART),
&job_id, &job_id,

View File

@ -668,7 +668,7 @@ int vl_method_set_unit_properties(sd_varlink *link, sd_json_variant *parameters,
return r; return r;
if (p.markers_found) if (p.markers_found)
unit->markers = unit_normalize_markers((unit->markers & ~p.markers_mask), p.markers); unit->markers = p.markers | (unit->markers & ~p.markers_mask);
return sd_varlink_reply(link, NULL); return sd_varlink_reply(link, NULL);
} }

View File

@ -59,8 +59,8 @@ static int systemctl_main(int argc, char *argv[]) {
{ "list-machines", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_list_machines }, { "list-machines", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_list_machines },
{ "clear-jobs", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_trivial_method }, { "clear-jobs", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_trivial_method },
{ "cancel", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_cancel }, { "cancel", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_cancel },
{ "start", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_start }, { "start", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_start },
{ "stop", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_start }, { "stop", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_start },
{ "condstop", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_start }, /* For compatibility with ALTLinux */ { "condstop", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_start }, /* For compatibility with ALTLinux */
{ "reload", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_start }, { "reload", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_start },
{ "restart", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_start }, { "restart", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_start },

View File

@ -1069,13 +1069,14 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--wait may not be combined with --no-block."); "--wait may not be combined with --no-block.");
bool do_reload_or_restart = streq_ptr(argv[optind], "reload-or-restart");
if (arg_marked) { if (arg_marked) {
if (!STRPTR_IN_SET(argv[optind], "reload-or-restart", "start", "stop")) if (!do_reload_or_restart)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--marked may only be used with 'reload-or-restart', 'start', or 'stop'."); "--marked may only be used with 'reload-or-restart'.");
if (optind + 1 < argc) if (optind + 1 < argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"No additional arguments allowed with '%s --marked'.", strna(argv[optind])); "No additional arguments allowed with 'reload-or-restart --marked'.");
if (arg_wait) if (arg_wait)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--marked --wait is not supported."); "--marked --wait is not supported.");
@ -1083,10 +1084,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--marked --show-transaction is not supported."); "--marked --show-transaction is not supported.");
} else if (STRPTR_IN_SET(argv[optind], "reload-or-restart", "start", "stop")) { } else if (do_reload_or_restart) {
if (optind + 1 >= argc) if (optind + 1 >= argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"List of units to %s is required.", strna(argv[optind])); "List of units to restart/reload is required.");
} }
if (arg_image && arg_root) if (arg_image && arg_root)

View File

@ -371,153 +371,18 @@ systemctl status 1
# --marked # --marked
systemctl restart "$UNIT_NAME" systemctl restart "$UNIT_NAME"
systemctl set-property "$UNIT_NAME" "Markers=needs-reload needs-restart" systemctl set-property "$UNIT_NAME" Markers=needs-restart
systemctl show -P Markers "$UNIT_NAME" | grep needs-restart systemctl show -P Markers "$UNIT_NAME" | grep needs-restart
systemctl show -P Markers "$UNIT_NAME" | grep -v needs-reload
systemctl reload-or-restart --marked systemctl reload-or-restart --marked
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-restart) (! systemctl show -P Markers "$UNIT_NAME" | grep needs-restart)
systemctl is-active "$UNIT_NAME"
systemctl set-property "$UNIT_NAME" "Markers=needs-reload needs-stop"
systemctl show -P Markers "$UNIT_NAME" | grep needs-stop
systemctl show -P Markers "$UNIT_NAME" | grep -v needs-reload
systemctl reload-or-restart --marked
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-stop)
(! systemctl is-active "$UNIT_NAME")
systemctl set-property "$UNIT_NAME" "Markers=needs-start"
systemctl show -P Markers "$UNIT_NAME" | grep needs-start
systemctl show -P Markers "$UNIT_NAME" | grep -v needs-stop
systemctl reload-or-restart --marked
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-start)
systemctl is-active "$UNIT_NAME"
systemctl set-property "$UNIT_NAME" "Markers=needs-start needs-stop"
systemctl show -P Markers "$UNIT_NAME" | grep needs-stop
systemctl show -P Markers "$UNIT_NAME" | grep -v needs-start
systemctl reload-or-restart --marked
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-stop)
(! systemctl is-active "$UNIT_NAME")
# Test marker normalization with incremental (+) syntax
# needs-start + +needs-restart → needs-restart (restart wins against start)
systemctl set-property "$UNIT_NAME" "Markers=needs-start"
systemctl set-property "$UNIT_NAME" "Markers=+needs-restart"
systemctl show -P Markers "$UNIT_NAME" | grep needs-restart
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-start)
systemctl set-property "$UNIT_NAME" "Markers="
# needs-restart + +needs-start → needs-restart (restart wins against start)
systemctl set-property "$UNIT_NAME" "Markers=needs-restart"
systemctl set-property "$UNIT_NAME" "Markers=+needs-start"
systemctl show -P Markers "$UNIT_NAME" | grep needs-restart
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-start)
systemctl set-property "$UNIT_NAME" "Markers="
# needs-restart + +needs-reload → needs-restart (reload loses against restart)
systemctl set-property "$UNIT_NAME" "Markers=needs-restart"
systemctl set-property "$UNIT_NAME" "Markers=+needs-reload"
systemctl show -P Markers "$UNIT_NAME" | grep needs-restart
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-reload)
systemctl set-property "$UNIT_NAME" "Markers="
# needs-stop + +needs-start → needs-start (start overrides stop)
systemctl set-property "$UNIT_NAME" "Markers=needs-stop"
systemctl set-property "$UNIT_NAME" "Markers=+needs-start"
systemctl show -P Markers "$UNIT_NAME" | grep needs-start
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-stop)
systemctl set-property "$UNIT_NAME" "Markers="
# anything + +needs-stop → needs-stop (stop wins against everything)
for marker in needs-start needs-restart needs-reload; do
systemctl set-property "$UNIT_NAME" "Markers=$marker"
systemctl set-property "$UNIT_NAME" "Markers=+needs-stop"
systemctl show -P Markers "$UNIT_NAME" | grep needs-stop
(! systemctl show -P Markers "$UNIT_NAME" | grep "$marker")
systemctl set-property "$UNIT_NAME" "Markers="
done
# needs-stop + +needs-reload → needs-stop (stop wins against reload)
systemctl set-property "$UNIT_NAME" "Markers=needs-stop"
systemctl set-property "$UNIT_NAME" "Markers=+needs-reload"
systemctl show -P Markers "$UNIT_NAME" | grep needs-stop
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-reload)
systemctl set-property "$UNIT_NAME" "Markers="
# again, but with varlinkctl instead # again, but with varlinkctl instead
systemctl restart "$UNIT_NAME" systemctl restart "$UNIT_NAME"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-reload\", \"needs-restart\"]}}" varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-restart\"]}}"
systemctl show -P Markers "$UNIT_NAME" | grep needs-restart systemctl show -P Markers "$UNIT_NAME" | grep needs-restart
systemctl show -P Markers "$UNIT_NAME" | grep -v needs-reload
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Manager.EnqueueMarkedJobs '{}' varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Manager.EnqueueMarkedJobs '{}'
timeout 30 bash -c "until systemctl list-jobs $UNIT_NAME | grep \"No jobs\" 2>/dev/null; do sleep 1; done" timeout 30 bash -c "until systemctl list-jobs $UNIT_NAME | grep \"No jobs\" 2>/dev/null; do sleep 1; done"
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-restart) (! systemctl show -P Markers "$UNIT_NAME" | grep needs-restart)
systemctl is-active "$UNIT_NAME"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-reload\", \"needs-stop\"]}}"
systemctl show -P Markers "$UNIT_NAME" | grep needs-stop
systemctl show -P Markers "$UNIT_NAME" | grep -v needs-reload
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Manager.EnqueueMarkedJobs '{}'
timeout 30 bash -c "until systemctl list-jobs $UNIT_NAME | grep \"No jobs\" 2>/dev/null; do sleep 1; done"
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-stop)
(! systemctl is-active "$UNIT_NAME")
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-start\"]}}"
systemctl show -P Markers "$UNIT_NAME" | grep needs-start
systemctl show -P Markers "$UNIT_NAME" | grep -v needs-stop
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Manager.EnqueueMarkedJobs '{}'
timeout 30 bash -c "until systemctl list-jobs $UNIT_NAME | grep \"No jobs\" 2>/dev/null; do sleep 1; done"
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-start)
systemctl is-active "$UNIT_NAME"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-start\", \"needs-stop\"]}}"
systemctl show -P Markers "$UNIT_NAME" | grep needs-stop
systemctl show -P Markers "$UNIT_NAME" | grep -v needs-start
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Manager.EnqueueMarkedJobs '{}'
timeout 30 bash -c "until systemctl list-jobs $UNIT_NAME | grep \"No jobs\" 2>/dev/null; do sleep 1; done"
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-stop)
(! systemctl is-active "$UNIT_NAME")
# Test marker normalization with incremental (+) syntax via varlinkctl
# needs-start + +needs-restart → needs-restart (restart wins against start)
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-start\"]}}"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"+needs-restart\"]}}"
systemctl show -P Markers "$UNIT_NAME" | grep needs-restart
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-start)
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": []}}"
# needs-restart + +needs-start → needs-restart (restart wins against start)
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-restart\"]}}"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"+needs-start\"]}}"
systemctl show -P Markers "$UNIT_NAME" | grep needs-restart
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-start)
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": []}}"
# needs-restart + +needs-reload → needs-restart (reload loses against restart)
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-restart\"]}}"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"+needs-reload\"]}}"
systemctl show -P Markers "$UNIT_NAME" | grep needs-restart
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-reload)
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": []}}"
# needs-stop + +needs-start → needs-start (start overrides stop)
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-stop\"]}}"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"+needs-start\"]}}"
systemctl show -P Markers "$UNIT_NAME" | grep needs-start
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-stop)
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": []}}"
# anything + +needs-stop → needs-stop (stop wins against everything)
for marker in needs-start needs-restart needs-reload; do
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"$marker\"]}}"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"+needs-stop\"]}}"
systemctl show -P Markers "$UNIT_NAME" | grep needs-stop
(! systemctl show -P Markers "$UNIT_NAME" | grep "$marker")
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": []}}"
done
# needs-stop + +needs-reload → needs-stop (stop wins against reload)
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"needs-stop\"]}}"
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": [\"+needs-reload\"]}}"
systemctl show -P Markers "$UNIT_NAME" | grep needs-stop
(! systemctl show -P Markers "$UNIT_NAME" | grep needs-reload)
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Unit.SetProperties "{\"runtime\": true, \"name\": \"$UNIT_NAME\", \"properties\": {\"Markers\": []}}"
# --dry-run with destructive verbs # --dry-run with destructive verbs
# kexec is skipped intentionally, as it requires a bit more involved setup # kexec is skipped intentionally, as it requires a bit more involved setup