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")
<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"/>
<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>
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",
_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,
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_;
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)'."),
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),
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",
(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");
} 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) {
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);
/* 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);
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;
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);