1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 17:35:35 +03:00

core: add Unit.Markers property

The property is never set by systemd, only reset after a stop or restart or
reload. It may externally be set to mark the unit for a later restart/reload.

I wasn't sure whether to configure the property only for the types where this
makes sense (Service, Swap, etc). But Restart() method is defined on the unit,
and also having this always under the same property name is more convenient.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-01-30 16:58:19 +01:00
parent 8c2524c7fd
commit ff68472a20
8 changed files with 130 additions and 4 deletions

View File

@ -1685,6 +1685,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 +1971,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 +2164,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>

View File

@ -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",

View File

@ -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_;

View File

@ -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)'."),
@ -864,6 +897,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),

View File

@ -28,6 +28,45 @@ static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) {
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",
@ -121,6 +160,7 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
(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");
@ -365,6 +405,13 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
} 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) {
@ -559,6 +606,15 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
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);

View File

@ -2390,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);

View File

@ -242,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;

View File

@ -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);