diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index c8937eeb26..feca6e8b80 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1985,7 +1985,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0), SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0), SD_BUS_PROPERTY("NNames", "u", property_get_n_names, 0, 0), - SD_BUS_PROPERTY("NFailedUnits", "u", property_get_n_failed_units, 0, 0), + SD_BUS_PROPERTY("NFailedUnits", "u", property_get_n_failed_units, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("NJobs", "u", property_get_n_jobs, 0, 0), SD_BUS_PROPERTY("NInstalledJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_installed_jobs), 0), SD_BUS_PROPERTY("NFailedJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_failed_jobs), 0), @@ -2138,5 +2138,23 @@ void bus_manager_send_reloading(Manager *m, bool active) { r = bus_foreach_bus(m, NULL, send_reloading, INT_TO_PTR(active)); if (r < 0) log_debug_errno(r, "Failed to send reloading signal: %m"); - +} + +static int send_changed_signal(sd_bus *bus, void *userdata) { + assert(bus); + + return sd_bus_emit_properties_changed_strv(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + NULL); +} + +void bus_manager_send_change_signal(Manager *m) { + int r; + + assert(m); + + r = bus_foreach_bus(m, NULL, send_changed_signal, NULL); + if (r < 0) + log_debug_errno(r, "Failed to send manager change signal: %m"); } diff --git a/src/core/dbus-manager.h b/src/core/dbus-manager.h index 3730deb576..5bdf6e17ab 100644 --- a/src/core/dbus-manager.h +++ b/src/core/dbus-manager.h @@ -27,3 +27,4 @@ extern const sd_bus_vtable bus_manager_vtable[]; void bus_manager_send_finished(Manager *m, usec_t firmware_usec, usec_t loader_usec, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec); void bus_manager_send_reloading(Manager *m, bool active); +void bus_manager_send_change_signal(Manager *m); diff --git a/src/core/manager.c b/src/core/manager.c index 79a9d54954..7966b387fc 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -3053,6 +3053,23 @@ const char *manager_get_runtime_prefix(Manager *m) { getenv("XDG_RUNTIME_DIR"); } +void manager_update_failed_units(Manager *m, Unit *u, bool failed) { + unsigned size; + + assert(m); + assert(u->manager == m); + + size = set_size(m->failed_units); + + if (failed) + set_put(m->failed_units, u); + else + set_remove(m->failed_units, u); + + if (set_size(m->failed_units) != size) + bus_manager_send_change_signal(m); +} + ManagerState manager_state(Manager *m) { Unit *u; diff --git a/src/core/manager.h b/src/core/manager.h index 4e33ba63f4..a1caab4d4e 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -362,5 +362,7 @@ const char *manager_get_runtime_prefix(Manager *m); ManagerState manager_state(Manager *m); +void manager_update_failed_units(Manager *m, Unit *u, bool failed); + const char *manager_state_to_string(ManagerState m) _const_; ManagerState manager_state_from_string(const char *s) _pure_; diff --git a/src/core/unit.c b/src/core/unit.c index 590ca3555a..63ccd671da 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -516,7 +516,7 @@ void unit_free(Unit *u) { free(u->cgroup_path); } - set_remove(u->manager->failed_units, u); + manager_update_failed_units(u->manager, u, false); set_remove(u->manager->startup_units, u); free(u->description); @@ -1797,10 +1797,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su } /* Keep track of failed units */ - if (ns == UNIT_FAILED) - set_put(u->manager->failed_units, u); - else - set_remove(u->manager->failed_units, u); + manager_update_failed_units(u->manager, u, ns == UNIT_FAILED); /* Make sure the cgroup is always removed when we become inactive */ if (UNIT_IS_INACTIVE_OR_FAILED(ns))