From: Zbigniew Jędrzejewski-Szmek Date: Sat, 30 Jan 2021 15:58:19 +0000 (+0100) Subject: core: add Unit.Markers property X-Git-Tag: v248-rc1~115^2~12 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ff68472a20c208121b69ea13586f3105a219bc14;p=thirdparty%2Fsystemd.git 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. --- diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 7543a617b78..13771a459a1 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -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 { + + @@ -2160,8 +2164,16 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { NeedDaemonReload is a boolean that indicates whether the configuration file this unit is loaded from (i.e. FragmentPath or SourcePath) has - changed since the configuration was read and hence whether a configuration reload is - recommended. + changed since the configuration was read and hence whether a configuration reload is recommended. + + + Markers is an array of string flags that can be set using + SetUnitProperties() to indicate that the service should be reloaded or + restarted. Currently known values are needs-restart and + needs-reload. 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. JobTimeoutUSec maps directly to the corresponding configuration setting in the unit file. diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index bb4fa1ec6bf..6fbb947f096 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -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", diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index ff05799c1d5..7742c5c0785 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -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_; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 90bf5514a3e..c9837df9a2e 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -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), diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c index ea4a57907e7..3f099248ce6 100644 --- a/src/core/unit-serialize.c +++ b/src/core/unit-serialize.c @@ -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); diff --git a/src/core/unit.c b/src/core/unit.c index d1525f55531..9c7f3dcdc03 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -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); diff --git a/src/core/unit.h b/src/core/unit.h index 457eba44a13..7c13e508788 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -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; diff --git a/src/udev/test-udev-builtin.c b/src/udev/test-udev-builtin.c index 1bd1dbddf52..21a8ea3fa6f 100644 --- a/src/udev/test-udev-builtin.c +++ b/src/udev/test-udev-builtin.c @@ -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);